All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 0/6] ARM: OMAP3+: minor PM core code cleanup
@ 2012-07-13 16:37 ` Tero Kristo
  0 siblings, 0 replies; 30+ messages in thread
From: Tero Kristo @ 2012-07-13 16:37 UTC (permalink / raw)
  To: linux-omap, paul, khilman; +Cc: linux-arm-kernel

Hi,

Following set moves some PRM related code away from PM core code to
PRM / HWMOD. This requires the hwmod cleanup set from Paul that
implements the setup_preprogram hooks for hwmods. Sending as RFC for
initial commenting.

This set does following:
- gets rid of the prcm interrupt handler from pm34xx.c
- removes iva_idle from pm34xx.c
- removes d2d_idle from pm34xx.c

There are some side-effects though, it looks like the reset statuses
for iva / d2d modules are rather flaky, and some failed hardreset
warnings are generated during boot. PM works fine though and the
modules are put to idle properly. Could use some ideas how to handle
this, maybe add a flag for ignoring the hardreset status completely...?

-Tero


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

* [RFC 0/6] ARM: OMAP3+: minor PM core code cleanup
@ 2012-07-13 16:37 ` Tero Kristo
  0 siblings, 0 replies; 30+ messages in thread
From: Tero Kristo @ 2012-07-13 16:37 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

Following set moves some PRM related code away from PM core code to
PRM / HWMOD. This requires the hwmod cleanup set from Paul that
implements the setup_preprogram hooks for hwmods. Sending as RFC for
initial commenting.

This set does following:
- gets rid of the prcm interrupt handler from pm34xx.c
- removes iva_idle from pm34xx.c
- removes d2d_idle from pm34xx.c

There are some side-effects though, it looks like the reset statuses
for iva / d2d modules are rather flaky, and some failed hardreset
warnings are generated during boot. PM works fine though and the
modules are put to idle properly. Could use some ideas how to handle
this, maybe add a flag for ignoring the hardreset status completely...?

-Tero

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

* [RFC 1/6] ARM: OMAP3: PRM: move prcm interrupt handlers to PRM driver code
  2012-07-13 16:37 ` Tero Kristo
@ 2012-07-13 16:37   ` Tero Kristo
  -1 siblings, 0 replies; 30+ messages in thread
From: Tero Kristo @ 2012-07-13 16:37 UTC (permalink / raw)
  To: linux-omap, paul, khilman; +Cc: linux-arm-kernel

PM code doesn't really care about the PRCM wakeup + io interrupts on
OMAP3, as these are used only for acking PRCM internal events, and the
IO chain handler is taken care of by hwmod code. Thus move the interrupt
handling logic from pm34xx.c to prm2xxx_3xxx.c file. This patch also
includes a minor cleanup for removing the priority handling and replacing
it with a mechanism for acking pending events. This gets rid of the need
for registering the shared interrupt handlers in specific order.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/pm34xx.c       |  109 +------------------------------
 arch/arm/mach-omap2/prcm-common.h  |   10 ++--
 arch/arm/mach-omap2/prm2xxx_3xxx.c |  124 ++++++++++++++++++++++++++++++++++--
 arch/arm/mach-omap2/prm2xxx_3xxx.h |    1 +
 arch/arm/mach-omap2/prm44xx.c      |    4 +-
 arch/arm/mach-omap2/prm_common.c   |   42 ++----------
 6 files changed, 138 insertions(+), 152 deletions(-)

diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index d25a9d8..474ed9d 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -133,85 +133,6 @@ static void omap3_save_secure_ram_context(void)
 	}
 }
 
-/*
- * PRCM Interrupt Handler Helper Function
- *
- * The purpose of this function is to clear any wake-up events latched
- * in the PRCM PM_WKST_x registers. It is possible that a wake-up event
- * may occur whilst attempting to clear a PM_WKST_x register and thus
- * set another bit in this register. A while loop is used to ensure
- * that any peripheral wake-up events occurring while attempting to
- * clear the PM_WKST_x are detected and cleared.
- */
-static int prcm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits)
-{
-	u32 wkst, fclk, iclk, clken;
-	u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
-	u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1;
-	u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1;
-	u16 grpsel_off = (regs == 3) ?
-		OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL;
-	int c = 0;
-
-	wkst = omap2_prm_read_mod_reg(module, wkst_off);
-	wkst &= omap2_prm_read_mod_reg(module, grpsel_off);
-	wkst &= ~ignore_bits;
-	if (wkst) {
-		iclk = omap2_cm_read_mod_reg(module, iclk_off);
-		fclk = omap2_cm_read_mod_reg(module, fclk_off);
-		while (wkst) {
-			clken = wkst;
-			omap2_cm_set_mod_reg_bits(clken, module, iclk_off);
-			/*
-			 * For USBHOST, we don't know whether HOST1 or
-			 * HOST2 woke us up, so enable both f-clocks
-			 */
-			if (module == OMAP3430ES2_USBHOST_MOD)
-				clken |= 1 << OMAP3430ES2_EN_USBHOST2_SHIFT;
-			omap2_cm_set_mod_reg_bits(clken, module, fclk_off);
-			omap2_prm_write_mod_reg(wkst, module, wkst_off);
-			wkst = omap2_prm_read_mod_reg(module, wkst_off);
-			wkst &= ~ignore_bits;
-			c++;
-		}
-		omap2_cm_write_mod_reg(iclk, module, iclk_off);
-		omap2_cm_write_mod_reg(fclk, module, fclk_off);
-	}
-
-	return c;
-}
-
-static irqreturn_t _prcm_int_handle_io(int irq, void *unused)
-{
-	int c;
-
-	c = prcm_clear_mod_irqs(WKUP_MOD, 1,
-		~(OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK));
-
-	return c ? IRQ_HANDLED : IRQ_NONE;
-}
-
-static irqreturn_t _prcm_int_handle_wakeup(int irq, void *unused)
-{
-	int c;
-
-	/*
-	 * Clear all except ST_IO and ST_IO_CHAIN for wkup module,
-	 * these are handled in a separate handler to avoid acking
-	 * IO events before parsing in mux code
-	 */
-	c = prcm_clear_mod_irqs(WKUP_MOD, 1,
-		OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK);
-	c += prcm_clear_mod_irqs(CORE_MOD, 1, 0);
-	c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1, 0);
-	if (omap_rev() > OMAP3430_REV_ES1_0) {
-		c += prcm_clear_mod_irqs(CORE_MOD, 3, 0);
-		c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1, 0);
-	}
-
-	return c ? IRQ_HANDLED : IRQ_NONE;
-}
-
 static void omap34xx_save_context(u32 *save)
 {
 	u32 val;
@@ -671,29 +592,10 @@ int __init omap3_pm_init(void)
 	 * supervised mode for powerdomains */
 	prcm_setup_regs();
 
-	ret = request_irq(omap_prcm_event_to_irq("wkup"),
-		_prcm_int_handle_wakeup, IRQF_NO_SUSPEND, "pm_wkup", NULL);
-
-	if (ret) {
-		pr_err("pm: Failed to request pm_wkup irq\n");
-		goto err1;
-	}
-
-	/* IO interrupt is shared with mux code */
-	ret = request_irq(omap_prcm_event_to_irq("io"),
-		_prcm_int_handle_io, IRQF_SHARED | IRQF_NO_SUSPEND, "pm_io",
-		omap3_pm_init);
-	enable_irq(omap_prcm_event_to_irq("io"));
-
-	if (ret) {
-		pr_err("pm: Failed to request pm_io irq\n");
-		goto err2;
-	}
-
 	ret = pwrdm_for_each(pwrdms_setup, NULL);
 	if (ret) {
 		pr_err("Failed to setup powerdomains\n");
-		goto err3;
+		goto err;
 	}
 
 	(void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
@@ -702,7 +604,7 @@ int __init omap3_pm_init(void)
 	if (mpu_pwrdm == NULL) {
 		pr_err("Failed to get mpu_pwrdm\n");
 		ret = -EINVAL;
-		goto err3;
+		goto err;
 	}
 
 	neon_pwrdm = pwrdm_lookup("neon_pwrdm");
@@ -750,14 +652,11 @@ int __init omap3_pm_init(void)
 	omap3_save_scratchpad_contents();
 	return ret;
 
-err3:
+err:
 	list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) {
 		list_del(&pwrst->node);
 		kfree(pwrst);
 	}
-	free_irq(omap_prcm_event_to_irq("io"), omap3_pm_init);
-err2:
-	free_irq(omap_prcm_event_to_irq("wkup"), NULL);
-err1:
+
 	return ret;
 }
diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
index fca23cb..ad23bb4 100644
--- a/arch/arm/mach-omap2/prcm-common.h
+++ b/arch/arm/mach-omap2/prcm-common.h
@@ -466,6 +466,7 @@ struct omap_prcm_irq {
  * @ocp_barrier: fn ptr to force buffered PRM writes to complete
  * @save_and_clear_irqen: fn ptr to save and clear IRQENABLE regs
  * @restore_irqen: fn ptr to save and clear IRQENABLE regs
+ * @ack_pending_events: fn ptr to ack pending events after handling
  * @saved_mask: IRQENABLE regs are saved here during suspend
  * @priority_mask: 1 bit per IRQ, set to 1 if omap_prcm_irq.priority = true
  * @base_irq: base dynamic IRQ number, returned from irq_alloc_descs() in init
@@ -487,18 +488,17 @@ struct omap_prcm_irq_setup {
 	void (*ocp_barrier)(void);
 	void (*save_and_clear_irqen)(u32 *saved_mask);
 	void (*restore_irqen)(u32 *saved_mask);
+	void (*ack_pending_events)(unsigned long *events);
 	u32 *saved_mask;
-	u32 *priority_mask;
 	int base_irq;
 	bool suspended;
 	bool suspend_save_flag;
 };
 
 /* OMAP_PRCM_IRQ: convenience macro for creating struct omap_prcm_irq records */
-#define OMAP_PRCM_IRQ(_name, _offset, _priority) {	\
-	.name = _name,					\
-	.offset = _offset,				\
-	.priority = _priority				\
+#define OMAP_PRCM_IRQ(_name, _offset) {	\
+	.name = _name,			\
+	.offset = _offset,		\
 	}
 
 extern void omap_prcm_irq_cleanup(void);
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
index a0309de..3761019 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
@@ -16,6 +16,7 @@
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/irq.h>
+#include <linux/interrupt.h>
 
 #include "common.h"
 #include <plat/cpu.h>
@@ -28,10 +29,11 @@
 #include "cm2xxx_3xxx.h"
 #include "prm-regbits-24xx.h"
 #include "prm-regbits-34xx.h"
+#include "cm-regbits-34xx.h"
 
 static const struct omap_prcm_irq omap3_prcm_irqs[] = {
-	OMAP_PRCM_IRQ("wkup",	0,	0),
-	OMAP_PRCM_IRQ("io",	9,	1),
+	OMAP_PRCM_IRQ("wkup",	0),
+	OMAP_PRCM_IRQ("io",	9),
 };
 
 static struct omap_prcm_irq_setup omap3_prcm_irq_setup = {
@@ -45,6 +47,7 @@ static struct omap_prcm_irq_setup omap3_prcm_irq_setup = {
 	.ocp_barrier		= &omap3xxx_prm_ocp_barrier,
 	.save_and_clear_irqen	= &omap3xxx_prm_save_and_clear_irqen,
 	.restore_irqen		= &omap3xxx_prm_restore_irqen,
+	.ack_pending_events	= &omap3xxx_prm_clear_wakeups,
 };
 
 u32 omap2_prm_read_mod_reg(s16 module, u16 idx)
@@ -349,18 +352,127 @@ static void __init omap3xxx_prm_enable_io_wakeup(void)
 					   PM_WKEN);
 }
 
+/**
+ * prcm_clear_mod_irqs - clear module level wakeup irqs for omap3
+ * @module: prm module to clear
+ * @regs: register set to use, either 1 or 3
+ *
+ * The purpose of this function is to clear any wake-up events latched
+ * in the PRCM PM_WKST_x registers. It is possible that a wake-up event
+ * may occur whilst attempting to clear a PM_WKST_x register and thus
+ * set another bit in this register. A while loop is used to ensure
+ * that any peripheral wake-up events occurring while attempting to
+ * clear the PM_WKST_x are detected and cleared. Returns the number
+ * of active wakeup events detected, or 0 if none.
+ */
+static int _prcm_clear_mod_irqs(s16 module, u8 regs)
+{
+	u32 wkst, fclk, iclk, clken;
+	u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
+	u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1;
+	u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1;
+	u16 grpsel_off = (regs == 3) ?
+		OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL;
+	int c = 0;
+
+	wkst = omap2_prm_read_mod_reg(module, wkst_off);
+	wkst &= omap2_prm_read_mod_reg(module, grpsel_off);
+	if (wkst) {
+		iclk = omap2_cm_read_mod_reg(module, iclk_off);
+		fclk = omap2_cm_read_mod_reg(module, fclk_off);
+		while (wkst) {
+			clken = wkst;
+			omap2_cm_set_mod_reg_bits(clken, module, iclk_off);
+			/*
+			 * For USBHOST, we don't know whether HOST1 or
+			 * HOST2 woke us up, so enable both f-clocks
+			 */
+			if (module == OMAP3430ES2_USBHOST_MOD)
+				clken |= 1 << OMAP3430ES2_EN_USBHOST2_SHIFT;
+			omap2_cm_set_mod_reg_bits(clken, module, fclk_off);
+			omap2_prm_write_mod_reg(wkst, module, wkst_off);
+			wkst = omap2_prm_read_mod_reg(module, wkst_off);
+			c++;
+		}
+		omap2_cm_write_mod_reg(iclk, module, iclk_off);
+		omap2_cm_write_mod_reg(fclk, module, fclk_off);
+	}
+
+	return c;
+}
+
+/**
+ * omap3xxx_prm_clear_wakeups - clears wakeup event sources
+ * @events: active PRCM interrupt event mask
+ *
+ * This function will first check if PRCM chain handler detected
+ * a wakeup event or not. If yes, it will continue to clear any
+ * pending wakeup events from PRCM module. Typically the module
+ * will generate an actual interrupt together with the wakeup event,
+ * which will then be handled separately by the driver code.
+ */
+void omap3xxx_prm_clear_wakeups(unsigned long *events)
+{
+	int c;
+
+	/*
+	 * If we didn't come here because of a wakeup event, do nothing
+	 */
+	if (!(events[0] & OMAP3430_WKUP_ST_MASK))
+		return;
+
+	c = _prcm_clear_mod_irqs(WKUP_MOD, 1);
+	c += _prcm_clear_mod_irqs(CORE_MOD, 1);
+	c += _prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1);
+	if (omap_rev() > OMAP3430_REV_ES1_0) {
+		c += _prcm_clear_mod_irqs(CORE_MOD, 3);
+		c += _prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
+	}
+}
+
+/**
+ * _prcm_int_handle_wakeup - dummy irq handler for prcm wakeup event
+ * @irq: not used, irq common API
+ * @unused: not used, irq common API
+ *
+ * Dummy handler for PRCM wakeup event interrupt. On software level,
+ * this handler doesn't do anything, but it is needed for hardware
+ * to function properly. Adding this handler will enable the wakeup
+ * event generation from PRCM, which is needed to get CPU out of
+ * WFI. Otherwise the CPU will get stuck on the WFI instruction
+ * indefinitely, as the MPU powerdomain remains idle.
+ */
+static irqreturn_t _prcm_int_handle_wakeup(int irq, void *unused)
+{
+	return IRQ_HANDLED;
+}
+
 static int __init omap3xxx_prcm_init(void)
 {
-	int ret = 0;
+	int ret;
 
 	if (cpu_is_omap34xx()) {
 		omap3xxx_prm_enable_io_wakeup();
 		ret = omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
-		if (!ret)
-			irq_set_status_flags(omap_prcm_event_to_irq("io"),
-					     IRQ_NOAUTOEN);
+		if (ret) {
+			pr_err("%s: failed to register chain handler: %d\n",
+				__func__, ret);
+			return ret;
+		}
+
+		ret = request_irq(omap_prcm_event_to_irq("wkup"),
+			_prcm_int_handle_wakeup, IRQF_NO_SUSPEND, "prcm_wkup",
+			NULL);
+		if (ret) {
+			pr_err("%s: failed to request prcm_wkup irq: %d\n",
+				__func__, ret);
+			goto err;
+		}
 	}
 
+	return 0;
+err:
+	omap_prcm_irq_cleanup();
 	return ret;
 }
 subsys_initcall(omap3xxx_prcm_init);
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h
index 1ba3d65..078df35 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.h
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h
@@ -322,6 +322,7 @@ extern void omap3xxx_prm_read_pending_irqs(unsigned long *events);
 extern void omap3xxx_prm_ocp_barrier(void);
 extern void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask);
 extern void omap3xxx_prm_restore_irqen(u32 *saved_mask);
+extern void omap3xxx_prm_clear_wakeups(unsigned long *events);
 
 #endif	/* CONFIG_ARCH_OMAP4 */
 
diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c
index bb727c2..fd26279 100644
--- a/arch/arm/mach-omap2/prm44xx.c
+++ b/arch/arm/mach-omap2/prm44xx.c
@@ -30,8 +30,8 @@
 #include "prminst44xx.h"
 
 static const struct omap_prcm_irq omap4_prcm_irqs[] = {
-	OMAP_PRCM_IRQ("wkup",   0,      0),
-	OMAP_PRCM_IRQ("io",     9,      1),
+	OMAP_PRCM_IRQ("wkup",	0),
+	OMAP_PRCM_IRQ("io",	9),
 };
 
 static struct omap_prcm_irq_setup omap4_prcm_irq_setup = {
diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c
index dfe00dd..4643651 100644
--- a/arch/arm/mach-omap2/prm_common.c
+++ b/arch/arm/mach-omap2/prm_common.c
@@ -57,21 +57,6 @@ static struct omap_prcm_irq_setup *prcm_irq_setup;
 /* Private functions */
 
 /*
- * Move priority events from events to priority_events array
- */
-static void omap_prcm_events_filter_priority(unsigned long *events,
-	unsigned long *priority_events)
-{
-	int i;
-
-	for (i = 0; i < prcm_irq_setup->nr_regs; i++) {
-		priority_events[i] =
-			events[i] & prcm_irq_setup->priority_mask[i];
-		events[i] ^= priority_events[i];
-	}
-}
-
-/*
  * PRCM Interrupt Handler
  *
  * This is a common handler for the OMAP PRCM interrupts. Pending
@@ -82,7 +67,6 @@ static void omap_prcm_events_filter_priority(unsigned long *events,
 static void omap_prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
 	unsigned long pending[OMAP_PRCM_MAX_NR_PENDING_REG];
-	unsigned long priority_pending[OMAP_PRCM_MAX_NR_PENDING_REG];
 	struct irq_chip *chip = irq_desc_get_chip(desc);
 	unsigned int virtirq;
 	int nr_irqs = prcm_irq_setup->nr_regs * 32;
@@ -113,20 +97,19 @@ static void omap_prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
 		if (find_first_bit(pending, nr_irqs) >= nr_irqs)
 			break;
 
-		omap_prcm_events_filter_priority(pending, priority_pending);
-
 		/*
 		 * Loop on all currently pending irqs so that new irqs
 		 * cannot starve previously pending irqs
 		 */
-
-		/* Serve priority events first */
-		for_each_set_bit(virtirq, priority_pending, nr_irqs)
-			generic_handle_irq(prcm_irq_setup->base_irq + virtirq);
-
-		/* Serve normal events next */
 		for_each_set_bit(virtirq, pending, nr_irqs)
 			generic_handle_irq(prcm_irq_setup->base_irq + virtirq);
+
+		/*
+		 * Ack pending events if needed, this will clean the
+		 * wakeup events on omap3
+		 */
+		if (prcm_irq_setup->ack_pending_events)
+			prcm_irq_setup->ack_pending_events(pending);
 	}
 	if (chip->irq_ack)
 		chip->irq_ack(&desc->irq_data);
@@ -191,9 +174,6 @@ void omap_prcm_irq_cleanup(void)
 	kfree(prcm_irq_setup->saved_mask);
 	prcm_irq_setup->saved_mask = NULL;
 
-	kfree(prcm_irq_setup->priority_mask);
-	prcm_irq_setup->priority_mask = NULL;
-
 	irq_set_chained_handler(prcm_irq_setup->irq, NULL);
 
 	if (prcm_irq_setup->base_irq > 0)
@@ -262,11 +242,8 @@ int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
 
 	prcm_irq_chips = kzalloc(sizeof(void *) * nr_regs, GFP_KERNEL);
 	prcm_irq_setup->saved_mask = kzalloc(sizeof(u32) * nr_regs, GFP_KERNEL);
-	prcm_irq_setup->priority_mask = kzalloc(sizeof(u32) * nr_regs,
-		GFP_KERNEL);
 
-	if (!prcm_irq_chips || !prcm_irq_setup->saved_mask ||
-	    !prcm_irq_setup->priority_mask) {
+	if (!prcm_irq_chips || !prcm_irq_setup->saved_mask) {
 		pr_err("PRCM: kzalloc failed\n");
 		goto err;
 	}
@@ -276,9 +253,6 @@ int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
 	for (i = 0; i < irq_setup->nr_irqs; i++) {
 		offset = irq_setup->irqs[i].offset;
 		mask[offset >> 5] |= 1 << (offset & 0x1f);
-		if (irq_setup->irqs[i].priority)
-			irq_setup->priority_mask[offset >> 5] |=
-				1 << (offset & 0x1f);
 	}
 
 	irq_set_chained_handler(irq_setup->irq, omap_prcm_irq_handler);
-- 
1.7.4.1


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

* [RFC 1/6] ARM: OMAP3: PRM: move prcm interrupt handlers to PRM driver code
@ 2012-07-13 16:37   ` Tero Kristo
  0 siblings, 0 replies; 30+ messages in thread
From: Tero Kristo @ 2012-07-13 16:37 UTC (permalink / raw)
  To: linux-arm-kernel

PM code doesn't really care about the PRCM wakeup + io interrupts on
OMAP3, as these are used only for acking PRCM internal events, and the
IO chain handler is taken care of by hwmod code. Thus move the interrupt
handling logic from pm34xx.c to prm2xxx_3xxx.c file. This patch also
includes a minor cleanup for removing the priority handling and replacing
it with a mechanism for acking pending events. This gets rid of the need
for registering the shared interrupt handlers in specific order.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/pm34xx.c       |  109 +------------------------------
 arch/arm/mach-omap2/prcm-common.h  |   10 ++--
 arch/arm/mach-omap2/prm2xxx_3xxx.c |  124 ++++++++++++++++++++++++++++++++++--
 arch/arm/mach-omap2/prm2xxx_3xxx.h |    1 +
 arch/arm/mach-omap2/prm44xx.c      |    4 +-
 arch/arm/mach-omap2/prm_common.c   |   42 ++----------
 6 files changed, 138 insertions(+), 152 deletions(-)

diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index d25a9d8..474ed9d 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -133,85 +133,6 @@ static void omap3_save_secure_ram_context(void)
 	}
 }
 
-/*
- * PRCM Interrupt Handler Helper Function
- *
- * The purpose of this function is to clear any wake-up events latched
- * in the PRCM PM_WKST_x registers. It is possible that a wake-up event
- * may occur whilst attempting to clear a PM_WKST_x register and thus
- * set another bit in this register. A while loop is used to ensure
- * that any peripheral wake-up events occurring while attempting to
- * clear the PM_WKST_x are detected and cleared.
- */
-static int prcm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits)
-{
-	u32 wkst, fclk, iclk, clken;
-	u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
-	u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1;
-	u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1;
-	u16 grpsel_off = (regs == 3) ?
-		OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL;
-	int c = 0;
-
-	wkst = omap2_prm_read_mod_reg(module, wkst_off);
-	wkst &= omap2_prm_read_mod_reg(module, grpsel_off);
-	wkst &= ~ignore_bits;
-	if (wkst) {
-		iclk = omap2_cm_read_mod_reg(module, iclk_off);
-		fclk = omap2_cm_read_mod_reg(module, fclk_off);
-		while (wkst) {
-			clken = wkst;
-			omap2_cm_set_mod_reg_bits(clken, module, iclk_off);
-			/*
-			 * For USBHOST, we don't know whether HOST1 or
-			 * HOST2 woke us up, so enable both f-clocks
-			 */
-			if (module == OMAP3430ES2_USBHOST_MOD)
-				clken |= 1 << OMAP3430ES2_EN_USBHOST2_SHIFT;
-			omap2_cm_set_mod_reg_bits(clken, module, fclk_off);
-			omap2_prm_write_mod_reg(wkst, module, wkst_off);
-			wkst = omap2_prm_read_mod_reg(module, wkst_off);
-			wkst &= ~ignore_bits;
-			c++;
-		}
-		omap2_cm_write_mod_reg(iclk, module, iclk_off);
-		omap2_cm_write_mod_reg(fclk, module, fclk_off);
-	}
-
-	return c;
-}
-
-static irqreturn_t _prcm_int_handle_io(int irq, void *unused)
-{
-	int c;
-
-	c = prcm_clear_mod_irqs(WKUP_MOD, 1,
-		~(OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK));
-
-	return c ? IRQ_HANDLED : IRQ_NONE;
-}
-
-static irqreturn_t _prcm_int_handle_wakeup(int irq, void *unused)
-{
-	int c;
-
-	/*
-	 * Clear all except ST_IO and ST_IO_CHAIN for wkup module,
-	 * these are handled in a separate handler to avoid acking
-	 * IO events before parsing in mux code
-	 */
-	c = prcm_clear_mod_irqs(WKUP_MOD, 1,
-		OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK);
-	c += prcm_clear_mod_irqs(CORE_MOD, 1, 0);
-	c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1, 0);
-	if (omap_rev() > OMAP3430_REV_ES1_0) {
-		c += prcm_clear_mod_irqs(CORE_MOD, 3, 0);
-		c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1, 0);
-	}
-
-	return c ? IRQ_HANDLED : IRQ_NONE;
-}
-
 static void omap34xx_save_context(u32 *save)
 {
 	u32 val;
@@ -671,29 +592,10 @@ int __init omap3_pm_init(void)
 	 * supervised mode for powerdomains */
 	prcm_setup_regs();
 
-	ret = request_irq(omap_prcm_event_to_irq("wkup"),
-		_prcm_int_handle_wakeup, IRQF_NO_SUSPEND, "pm_wkup", NULL);
-
-	if (ret) {
-		pr_err("pm: Failed to request pm_wkup irq\n");
-		goto err1;
-	}
-
-	/* IO interrupt is shared with mux code */
-	ret = request_irq(omap_prcm_event_to_irq("io"),
-		_prcm_int_handle_io, IRQF_SHARED | IRQF_NO_SUSPEND, "pm_io",
-		omap3_pm_init);
-	enable_irq(omap_prcm_event_to_irq("io"));
-
-	if (ret) {
-		pr_err("pm: Failed to request pm_io irq\n");
-		goto err2;
-	}
-
 	ret = pwrdm_for_each(pwrdms_setup, NULL);
 	if (ret) {
 		pr_err("Failed to setup powerdomains\n");
-		goto err3;
+		goto err;
 	}
 
 	(void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
@@ -702,7 +604,7 @@ int __init omap3_pm_init(void)
 	if (mpu_pwrdm == NULL) {
 		pr_err("Failed to get mpu_pwrdm\n");
 		ret = -EINVAL;
-		goto err3;
+		goto err;
 	}
 
 	neon_pwrdm = pwrdm_lookup("neon_pwrdm");
@@ -750,14 +652,11 @@ int __init omap3_pm_init(void)
 	omap3_save_scratchpad_contents();
 	return ret;
 
-err3:
+err:
 	list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) {
 		list_del(&pwrst->node);
 		kfree(pwrst);
 	}
-	free_irq(omap_prcm_event_to_irq("io"), omap3_pm_init);
-err2:
-	free_irq(omap_prcm_event_to_irq("wkup"), NULL);
-err1:
+
 	return ret;
 }
diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
index fca23cb..ad23bb4 100644
--- a/arch/arm/mach-omap2/prcm-common.h
+++ b/arch/arm/mach-omap2/prcm-common.h
@@ -466,6 +466,7 @@ struct omap_prcm_irq {
  * @ocp_barrier: fn ptr to force buffered PRM writes to complete
  * @save_and_clear_irqen: fn ptr to save and clear IRQENABLE regs
  * @restore_irqen: fn ptr to save and clear IRQENABLE regs
+ * @ack_pending_events: fn ptr to ack pending events after handling
  * @saved_mask: IRQENABLE regs are saved here during suspend
  * @priority_mask: 1 bit per IRQ, set to 1 if omap_prcm_irq.priority = true
  * @base_irq: base dynamic IRQ number, returned from irq_alloc_descs() in init
@@ -487,18 +488,17 @@ struct omap_prcm_irq_setup {
 	void (*ocp_barrier)(void);
 	void (*save_and_clear_irqen)(u32 *saved_mask);
 	void (*restore_irqen)(u32 *saved_mask);
+	void (*ack_pending_events)(unsigned long *events);
 	u32 *saved_mask;
-	u32 *priority_mask;
 	int base_irq;
 	bool suspended;
 	bool suspend_save_flag;
 };
 
 /* OMAP_PRCM_IRQ: convenience macro for creating struct omap_prcm_irq records */
-#define OMAP_PRCM_IRQ(_name, _offset, _priority) {	\
-	.name = _name,					\
-	.offset = _offset,				\
-	.priority = _priority				\
+#define OMAP_PRCM_IRQ(_name, _offset) {	\
+	.name = _name,			\
+	.offset = _offset,		\
 	}
 
 extern void omap_prcm_irq_cleanup(void);
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
index a0309de..3761019 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
@@ -16,6 +16,7 @@
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/irq.h>
+#include <linux/interrupt.h>
 
 #include "common.h"
 #include <plat/cpu.h>
@@ -28,10 +29,11 @@
 #include "cm2xxx_3xxx.h"
 #include "prm-regbits-24xx.h"
 #include "prm-regbits-34xx.h"
+#include "cm-regbits-34xx.h"
 
 static const struct omap_prcm_irq omap3_prcm_irqs[] = {
-	OMAP_PRCM_IRQ("wkup",	0,	0),
-	OMAP_PRCM_IRQ("io",	9,	1),
+	OMAP_PRCM_IRQ("wkup",	0),
+	OMAP_PRCM_IRQ("io",	9),
 };
 
 static struct omap_prcm_irq_setup omap3_prcm_irq_setup = {
@@ -45,6 +47,7 @@ static struct omap_prcm_irq_setup omap3_prcm_irq_setup = {
 	.ocp_barrier		= &omap3xxx_prm_ocp_barrier,
 	.save_and_clear_irqen	= &omap3xxx_prm_save_and_clear_irqen,
 	.restore_irqen		= &omap3xxx_prm_restore_irqen,
+	.ack_pending_events	= &omap3xxx_prm_clear_wakeups,
 };
 
 u32 omap2_prm_read_mod_reg(s16 module, u16 idx)
@@ -349,18 +352,127 @@ static void __init omap3xxx_prm_enable_io_wakeup(void)
 					   PM_WKEN);
 }
 
+/**
+ * prcm_clear_mod_irqs - clear module level wakeup irqs for omap3
+ * @module: prm module to clear
+ * @regs: register set to use, either 1 or 3
+ *
+ * The purpose of this function is to clear any wake-up events latched
+ * in the PRCM PM_WKST_x registers. It is possible that a wake-up event
+ * may occur whilst attempting to clear a PM_WKST_x register and thus
+ * set another bit in this register. A while loop is used to ensure
+ * that any peripheral wake-up events occurring while attempting to
+ * clear the PM_WKST_x are detected and cleared. Returns the number
+ * of active wakeup events detected, or 0 if none.
+ */
+static int _prcm_clear_mod_irqs(s16 module, u8 regs)
+{
+	u32 wkst, fclk, iclk, clken;
+	u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
+	u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1;
+	u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1;
+	u16 grpsel_off = (regs == 3) ?
+		OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL;
+	int c = 0;
+
+	wkst = omap2_prm_read_mod_reg(module, wkst_off);
+	wkst &= omap2_prm_read_mod_reg(module, grpsel_off);
+	if (wkst) {
+		iclk = omap2_cm_read_mod_reg(module, iclk_off);
+		fclk = omap2_cm_read_mod_reg(module, fclk_off);
+		while (wkst) {
+			clken = wkst;
+			omap2_cm_set_mod_reg_bits(clken, module, iclk_off);
+			/*
+			 * For USBHOST, we don't know whether HOST1 or
+			 * HOST2 woke us up, so enable both f-clocks
+			 */
+			if (module == OMAP3430ES2_USBHOST_MOD)
+				clken |= 1 << OMAP3430ES2_EN_USBHOST2_SHIFT;
+			omap2_cm_set_mod_reg_bits(clken, module, fclk_off);
+			omap2_prm_write_mod_reg(wkst, module, wkst_off);
+			wkst = omap2_prm_read_mod_reg(module, wkst_off);
+			c++;
+		}
+		omap2_cm_write_mod_reg(iclk, module, iclk_off);
+		omap2_cm_write_mod_reg(fclk, module, fclk_off);
+	}
+
+	return c;
+}
+
+/**
+ * omap3xxx_prm_clear_wakeups - clears wakeup event sources
+ * @events: active PRCM interrupt event mask
+ *
+ * This function will first check if PRCM chain handler detected
+ * a wakeup event or not. If yes, it will continue to clear any
+ * pending wakeup events from PRCM module. Typically the module
+ * will generate an actual interrupt together with the wakeup event,
+ * which will then be handled separately by the driver code.
+ */
+void omap3xxx_prm_clear_wakeups(unsigned long *events)
+{
+	int c;
+
+	/*
+	 * If we didn't come here because of a wakeup event, do nothing
+	 */
+	if (!(events[0] & OMAP3430_WKUP_ST_MASK))
+		return;
+
+	c = _prcm_clear_mod_irqs(WKUP_MOD, 1);
+	c += _prcm_clear_mod_irqs(CORE_MOD, 1);
+	c += _prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1);
+	if (omap_rev() > OMAP3430_REV_ES1_0) {
+		c += _prcm_clear_mod_irqs(CORE_MOD, 3);
+		c += _prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
+	}
+}
+
+/**
+ * _prcm_int_handle_wakeup - dummy irq handler for prcm wakeup event
+ * @irq: not used, irq common API
+ * @unused: not used, irq common API
+ *
+ * Dummy handler for PRCM wakeup event interrupt. On software level,
+ * this handler doesn't do anything, but it is needed for hardware
+ * to function properly. Adding this handler will enable the wakeup
+ * event generation from PRCM, which is needed to get CPU out of
+ * WFI. Otherwise the CPU will get stuck on the WFI instruction
+ * indefinitely, as the MPU powerdomain remains idle.
+ */
+static irqreturn_t _prcm_int_handle_wakeup(int irq, void *unused)
+{
+	return IRQ_HANDLED;
+}
+
 static int __init omap3xxx_prcm_init(void)
 {
-	int ret = 0;
+	int ret;
 
 	if (cpu_is_omap34xx()) {
 		omap3xxx_prm_enable_io_wakeup();
 		ret = omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
-		if (!ret)
-			irq_set_status_flags(omap_prcm_event_to_irq("io"),
-					     IRQ_NOAUTOEN);
+		if (ret) {
+			pr_err("%s: failed to register chain handler: %d\n",
+				__func__, ret);
+			return ret;
+		}
+
+		ret = request_irq(omap_prcm_event_to_irq("wkup"),
+			_prcm_int_handle_wakeup, IRQF_NO_SUSPEND, "prcm_wkup",
+			NULL);
+		if (ret) {
+			pr_err("%s: failed to request prcm_wkup irq: %d\n",
+				__func__, ret);
+			goto err;
+		}
 	}
 
+	return 0;
+err:
+	omap_prcm_irq_cleanup();
 	return ret;
 }
 subsys_initcall(omap3xxx_prcm_init);
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h
index 1ba3d65..078df35 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.h
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h
@@ -322,6 +322,7 @@ extern void omap3xxx_prm_read_pending_irqs(unsigned long *events);
 extern void omap3xxx_prm_ocp_barrier(void);
 extern void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask);
 extern void omap3xxx_prm_restore_irqen(u32 *saved_mask);
+extern void omap3xxx_prm_clear_wakeups(unsigned long *events);
 
 #endif	/* CONFIG_ARCH_OMAP4 */
 
diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c
index bb727c2..fd26279 100644
--- a/arch/arm/mach-omap2/prm44xx.c
+++ b/arch/arm/mach-omap2/prm44xx.c
@@ -30,8 +30,8 @@
 #include "prminst44xx.h"
 
 static const struct omap_prcm_irq omap4_prcm_irqs[] = {
-	OMAP_PRCM_IRQ("wkup",   0,      0),
-	OMAP_PRCM_IRQ("io",     9,      1),
+	OMAP_PRCM_IRQ("wkup",	0),
+	OMAP_PRCM_IRQ("io",	9),
 };
 
 static struct omap_prcm_irq_setup omap4_prcm_irq_setup = {
diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c
index dfe00dd..4643651 100644
--- a/arch/arm/mach-omap2/prm_common.c
+++ b/arch/arm/mach-omap2/prm_common.c
@@ -57,21 +57,6 @@ static struct omap_prcm_irq_setup *prcm_irq_setup;
 /* Private functions */
 
 /*
- * Move priority events from events to priority_events array
- */
-static void omap_prcm_events_filter_priority(unsigned long *events,
-	unsigned long *priority_events)
-{
-	int i;
-
-	for (i = 0; i < prcm_irq_setup->nr_regs; i++) {
-		priority_events[i] =
-			events[i] & prcm_irq_setup->priority_mask[i];
-		events[i] ^= priority_events[i];
-	}
-}
-
-/*
  * PRCM Interrupt Handler
  *
  * This is a common handler for the OMAP PRCM interrupts. Pending
@@ -82,7 +67,6 @@ static void omap_prcm_events_filter_priority(unsigned long *events,
 static void omap_prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
 	unsigned long pending[OMAP_PRCM_MAX_NR_PENDING_REG];
-	unsigned long priority_pending[OMAP_PRCM_MAX_NR_PENDING_REG];
 	struct irq_chip *chip = irq_desc_get_chip(desc);
 	unsigned int virtirq;
 	int nr_irqs = prcm_irq_setup->nr_regs * 32;
@@ -113,20 +97,19 @@ static void omap_prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
 		if (find_first_bit(pending, nr_irqs) >= nr_irqs)
 			break;
 
-		omap_prcm_events_filter_priority(pending, priority_pending);
-
 		/*
 		 * Loop on all currently pending irqs so that new irqs
 		 * cannot starve previously pending irqs
 		 */
-
-		/* Serve priority events first */
-		for_each_set_bit(virtirq, priority_pending, nr_irqs)
-			generic_handle_irq(prcm_irq_setup->base_irq + virtirq);
-
-		/* Serve normal events next */
 		for_each_set_bit(virtirq, pending, nr_irqs)
 			generic_handle_irq(prcm_irq_setup->base_irq + virtirq);
+
+		/*
+		 * Ack pending events if needed, this will clean the
+		 * wakeup events on omap3
+		 */
+		if (prcm_irq_setup->ack_pending_events)
+			prcm_irq_setup->ack_pending_events(pending);
 	}
 	if (chip->irq_ack)
 		chip->irq_ack(&desc->irq_data);
@@ -191,9 +174,6 @@ void omap_prcm_irq_cleanup(void)
 	kfree(prcm_irq_setup->saved_mask);
 	prcm_irq_setup->saved_mask = NULL;
 
-	kfree(prcm_irq_setup->priority_mask);
-	prcm_irq_setup->priority_mask = NULL;
-
 	irq_set_chained_handler(prcm_irq_setup->irq, NULL);
 
 	if (prcm_irq_setup->base_irq > 0)
@@ -262,11 +242,8 @@ int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
 
 	prcm_irq_chips = kzalloc(sizeof(void *) * nr_regs, GFP_KERNEL);
 	prcm_irq_setup->saved_mask = kzalloc(sizeof(u32) * nr_regs, GFP_KERNEL);
-	prcm_irq_setup->priority_mask = kzalloc(sizeof(u32) * nr_regs,
-		GFP_KERNEL);
 
-	if (!prcm_irq_chips || !prcm_irq_setup->saved_mask ||
-	    !prcm_irq_setup->priority_mask) {
+	if (!prcm_irq_chips || !prcm_irq_setup->saved_mask) {
 		pr_err("PRCM: kzalloc failed\n");
 		goto err;
 	}
@@ -276,9 +253,6 @@ int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
 	for (i = 0; i < irq_setup->nr_irqs; i++) {
 		offset = irq_setup->irqs[i].offset;
 		mask[offset >> 5] |= 1 << (offset & 0x1f);
-		if (irq_setup->irqs[i].priority)
-			irq_setup->priority_mask[offset >> 5] |=
-				1 << (offset & 0x1f);
 	}
 
 	irq_set_chained_handler(irq_setup->irq, omap_prcm_irq_handler);
-- 
1.7.4.1

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

* [RFC 2/6] ARM: OMAP3: clock data: prevent IVA2 DPLL low power stop mode
  2012-07-13 16:37 ` Tero Kristo
@ 2012-07-13 16:37   ` Tero Kristo
  -1 siblings, 0 replies; 30+ messages in thread
From: Tero Kristo @ 2012-07-13 16:37 UTC (permalink / raw)
  To: linux-omap, paul, khilman; +Cc: linux-arm-kernel

If IVA2 DPLL is in low power stop mode, this will prevent IVA2
powerdomain sleep transition. Typically the DPLL is in locked
autoidle mode, which will allow sleep. With the wrong config,
the DPLL will end up in the wrong mode if IVA2 clock is first
enabled, then disabled by SW. This happens for example once
IVA2 hwmod reset sequence is implemented properly within hwmod
preprogram hook, as the IVA2 clock must be enabled during this.

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

diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c
index 1efdec2..3b7e9c8 100644
--- a/arch/arm/mach-omap2/clock3xxx_data.c
+++ b/arch/arm/mach-omap2/clock3xxx_data.c
@@ -353,8 +353,7 @@ static struct dpll_data dpll2_dd = {
 	.freqsel_mask	= OMAP3430_IVA2_DPLL_FREQSEL_MASK,
 	.control_reg	= OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKEN_PLL),
 	.enable_mask	= OMAP3430_EN_IVA2_DPLL_MASK,
-	.modes		= (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED) |
-				(1 << DPLL_LOW_POWER_BYPASS),
+	.modes		= (1 << DPLL_LOCKED) | (1 << DPLL_LOW_POWER_BYPASS),
 	.auto_recal_bit	= OMAP3430_EN_IVA2_DPLL_DRIFTGUARD_SHIFT,
 	.recal_en_bit	= OMAP3430_PRM_IRQENABLE_MPU_IVA2_DPLL_RECAL_EN_SHIFT,
 	.recal_st_bit	= OMAP3430_PRM_IRQSTATUS_MPU_IVA2_DPLL_ST_SHIFT,
-- 
1.7.4.1


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

* [RFC 2/6] ARM: OMAP3: clock data: prevent IVA2 DPLL low power stop mode
@ 2012-07-13 16:37   ` Tero Kristo
  0 siblings, 0 replies; 30+ messages in thread
From: Tero Kristo @ 2012-07-13 16:37 UTC (permalink / raw)
  To: linux-arm-kernel

If IVA2 DPLL is in low power stop mode, this will prevent IVA2
powerdomain sleep transition. Typically the DPLL is in locked
autoidle mode, which will allow sleep. With the wrong config,
the DPLL will end up in the wrong mode if IVA2 clock is first
enabled, then disabled by SW. This happens for example once
IVA2 hwmod reset sequence is implemented properly within hwmod
preprogram hook, as the IVA2 clock must be enabled during this.

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

diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c
index 1efdec2..3b7e9c8 100644
--- a/arch/arm/mach-omap2/clock3xxx_data.c
+++ b/arch/arm/mach-omap2/clock3xxx_data.c
@@ -353,8 +353,7 @@ static struct dpll_data dpll2_dd = {
 	.freqsel_mask	= OMAP3430_IVA2_DPLL_FREQSEL_MASK,
 	.control_reg	= OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKEN_PLL),
 	.enable_mask	= OMAP3430_EN_IVA2_DPLL_MASK,
-	.modes		= (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED) |
-				(1 << DPLL_LOW_POWER_BYPASS),
+	.modes		= (1 << DPLL_LOCKED) | (1 << DPLL_LOW_POWER_BYPASS),
 	.auto_recal_bit	= OMAP3430_EN_IVA2_DPLL_DRIFTGUARD_SHIFT,
 	.recal_en_bit	= OMAP3430_PRM_IRQENABLE_MPU_IVA2_DPLL_RECAL_EN_SHIFT,
 	.recal_st_bit	= OMAP3430_PRM_IRQSTATUS_MPU_IVA2_DPLL_ST_SHIFT,
-- 
1.7.4.1

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

* [RFC 3/6] ARM: OMAP3: hwmod data: fix iva2 reset info
  2012-07-13 16:37 ` Tero Kristo
@ 2012-07-13 16:37   ` Tero Kristo
  -1 siblings, 0 replies; 30+ messages in thread
From: Tero Kristo @ 2012-07-13 16:37 UTC (permalink / raw)
  To: linux-omap, paul, khilman; +Cc: linux-arm-kernel

IVA2 hwmod resets were missing the status bit offsets. Also, as the
hwmod itself didn't have prcm info at all, resetting iva hwmod was
accessing some bogus memory addresses. Added both infos to fix this.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/cm-regbits-34xx.h      |    1 +
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |   15 ++++++++++++---
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h
index 8083a8c..90d150c8 100644
--- a/arch/arm/mach-omap2/cm-regbits-34xx.h
+++ b/arch/arm/mach-omap2/cm-regbits-34xx.h
@@ -67,6 +67,7 @@
 #define OMAP3430_EN_IVA2_DPLL_MASK			(0x7 << 0)
 
 /* CM_IDLEST_IVA2 */
+#define OMAP3430_ST_IVA2_SHIFT				0
 #define OMAP3430_ST_IVA2_MASK				(1 << 0)
 
 /* CM_IDLEST_PLL_IVA2 */
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index f8ac9e7..98bc6f9 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -100,9 +100,9 @@ static struct omap_hwmod omap3xxx_mpu_hwmod = {
 
 /* IVA2 (IVA2) */
 static struct omap_hwmod_rst_info omap3xxx_iva_resets[] = {
-	{ .name = "logic", .rst_shift = 0 },
-	{ .name = "seq0", .rst_shift = 1 },
-	{ .name = "seq1", .rst_shift = 2 },
+	{ .name = "logic", .rst_shift = 0, .st_shift = 8 },
+	{ .name = "seq0", .rst_shift = 1, .st_shift = 9 },
+	{ .name = "seq1", .rst_shift = 2, .st_shift = 10 },
 };
 
 static struct omap_hwmod omap3xxx_iva_hwmod = {
@@ -112,6 +112,15 @@ static struct omap_hwmod omap3xxx_iva_hwmod = {
 	.rst_lines	= omap3xxx_iva_resets,
 	.rst_lines_cnt	= ARRAY_SIZE(omap3xxx_iva_resets),
 	.main_clk	= "iva2_ck",
+	.prcm = {
+		.omap2 = {
+			.module_offs = OMAP3430_IVA2_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_CM_FCLKEN_IVA2_EN_IVA2_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_IVA2_SHIFT,
+		}
+	},
 };
 
 /* timer class */
-- 
1.7.4.1


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

* [RFC 3/6] ARM: OMAP3: hwmod data: fix iva2 reset info
@ 2012-07-13 16:37   ` Tero Kristo
  0 siblings, 0 replies; 30+ messages in thread
From: Tero Kristo @ 2012-07-13 16:37 UTC (permalink / raw)
  To: linux-arm-kernel

IVA2 hwmod resets were missing the status bit offsets. Also, as the
hwmod itself didn't have prcm info at all, resetting iva hwmod was
accessing some bogus memory addresses. Added both infos to fix this.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/cm-regbits-34xx.h      |    1 +
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |   15 ++++++++++++---
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h
index 8083a8c..90d150c8 100644
--- a/arch/arm/mach-omap2/cm-regbits-34xx.h
+++ b/arch/arm/mach-omap2/cm-regbits-34xx.h
@@ -67,6 +67,7 @@
 #define OMAP3430_EN_IVA2_DPLL_MASK			(0x7 << 0)
 
 /* CM_IDLEST_IVA2 */
+#define OMAP3430_ST_IVA2_SHIFT				0
 #define OMAP3430_ST_IVA2_MASK				(1 << 0)
 
 /* CM_IDLEST_PLL_IVA2 */
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index f8ac9e7..98bc6f9 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -100,9 +100,9 @@ static struct omap_hwmod omap3xxx_mpu_hwmod = {
 
 /* IVA2 (IVA2) */
 static struct omap_hwmod_rst_info omap3xxx_iva_resets[] = {
-	{ .name = "logic", .rst_shift = 0 },
-	{ .name = "seq0", .rst_shift = 1 },
-	{ .name = "seq1", .rst_shift = 2 },
+	{ .name = "logic", .rst_shift = 0, .st_shift = 8 },
+	{ .name = "seq0", .rst_shift = 1, .st_shift = 9 },
+	{ .name = "seq1", .rst_shift = 2, .st_shift = 10 },
 };
 
 static struct omap_hwmod omap3xxx_iva_hwmod = {
@@ -112,6 +112,15 @@ static struct omap_hwmod omap3xxx_iva_hwmod = {
 	.rst_lines	= omap3xxx_iva_resets,
 	.rst_lines_cnt	= ARRAY_SIZE(omap3xxx_iva_resets),
 	.main_clk	= "iva2_ck",
+	.prcm = {
+		.omap2 = {
+			.module_offs = OMAP3430_IVA2_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_CM_FCLKEN_IVA2_EN_IVA2_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_IVA2_SHIFT,
+		}
+	},
 };
 
 /* timer class */
-- 
1.7.4.1

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

* [RFC 4/6] ARM: OMAP3: hwmod data: add custom setup_preprogram for iva hwmod
  2012-07-13 16:37 ` Tero Kristo
@ 2012-07-13 16:37   ` Tero Kristo
  -1 siblings, 0 replies; 30+ messages in thread
From: Tero Kristo @ 2012-07-13 16:37 UTC (permalink / raw)
  To: linux-omap, paul, khilman; +Cc: linux-arm-kernel

IVA2 module must be properly put to idle mode during boot, as it is
possible that it is enabled by bootloader, and this will prevent
core retention/off. Previously this was done by an init time hook
from pm34xx.c file, but this functionality is now moved within
hwmod setup_preprogram hook for iva hwmod.

This patch introduces following warning during boot:

     omap_hwmod: iva: failed to hardreset

This is generated by asserting the 'logic' hardreset for IVA2
hwmod. However, this warning is not fatal, and doesn't cause any
functional problems.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |   13 +++++-
 arch/arm/mach-omap2/pm34xx.c               |   49 -------------------
 include/linux/platform_data/omap3-iva.h    |   73 ++++++++++++++++++++++++++++
 3 files changed, 85 insertions(+), 50 deletions(-)
 create mode 100644 include/linux/platform_data/omap3-iva.h

diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 98bc6f9..1ef6c90 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -14,6 +14,12 @@
  *
  * XXX these should be marked initdata for multi-OMAP kernels
  */
+
+#include <linux/io.h>
+#include "control.h"
+#include "iomap.h"
+#include <linux/platform_data/omap3-iva.h>
+
 #include <plat/omap_hwmod.h>
 #include <mach/irqs.h>
 #include <plat/cpu.h>
@@ -105,9 +111,14 @@ static struct omap_hwmod_rst_info omap3xxx_iva_resets[] = {
 	{ .name = "seq1", .rst_shift = 2, .st_shift = 10 },
 };
 
+static struct omap_hwmod_class omap3xxx_iva_hwmod_class = {
+	.name			= "iva",
+	.setup_preprogram	= hwmod_iva_preprogram,
+};
+
 static struct omap_hwmod omap3xxx_iva_hwmod = {
 	.name		= "iva",
-	.class		= &iva_hwmod_class,
+	.class		= &omap3xxx_iva_hwmod_class,
 	.clkdm_name	= "iva2_clkdm",
 	.rst_lines	= omap3xxx_iva_resets,
 	.rst_lines_cnt	= ARRAY_SIZE(omap3xxx_iva_resets),
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 474ed9d..d407b32 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -333,54 +333,6 @@ restore:
 
 #endif /* CONFIG_SUSPEND */
 
-
-/**
- * omap3_iva_idle(): ensure IVA is in idle so it can be put into
- *                   retention
- *
- * In cases where IVA2 is activated by bootcode, it may prevent
- * full-chip retention or off-mode because it is not idle.  This
- * function forces the IVA2 into idle state so it can go
- * into retention/off and thus allow full-chip retention/off.
- *
- **/
-static void __init omap3_iva_idle(void)
-{
-	/* ensure IVA2 clock is disabled */
-	omap2_cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
-
-	/* if no clock activity, nothing else to do */
-	if (!(omap2_cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSTST) &
-	      OMAP3430_CLKACTIVITY_IVA2_MASK))
-		return;
-
-	/* Reset IVA2 */
-	omap2_prm_write_mod_reg(OMAP3430_RST1_IVA2_MASK |
-			  OMAP3430_RST2_IVA2_MASK |
-			  OMAP3430_RST3_IVA2_MASK,
-			  OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
-
-	/* Enable IVA2 clock */
-	omap2_cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2_MASK,
-			 OMAP3430_IVA2_MOD, CM_FCLKEN);
-
-	/* Set IVA2 boot mode to 'idle' */
-	omap_ctrl_writel(OMAP3_IVA2_BOOTMOD_IDLE,
-			 OMAP343X_CONTROL_IVA2_BOOTMOD);
-
-	/* Un-reset IVA2 */
-	omap2_prm_write_mod_reg(0, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
-
-	/* Disable IVA2 clock */
-	omap2_cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
-
-	/* Reset IVA2 */
-	omap2_prm_write_mod_reg(OMAP3430_RST1_IVA2_MASK |
-			  OMAP3430_RST2_IVA2_MASK |
-			  OMAP3430_RST3_IVA2_MASK,
-			  OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
-}
-
 static void __init omap3_d2d_idle(void)
 {
 	u16 mask, padconf;
@@ -478,7 +430,6 @@ static void __init prcm_setup_regs(void)
 	/* Clear any pending PRCM interrupts */
 	omap2_prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
 
-	omap3_iva_idle();
 	omap3_d2d_idle();
 }
 
diff --git a/include/linux/platform_data/omap3-iva.h b/include/linux/platform_data/omap3-iva.h
new file mode 100644
index 0000000..742349a
--- /dev/null
+++ b/include/linux/platform_data/omap3-iva.h
@@ -0,0 +1,73 @@
+/*
+ * OMAP3 IVA IP block integration
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ * Tero Kristo
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#ifndef __LINUX_PLATFORM_DATA_OMAP3_IVA_H__
+#define __LINUX_PLATFORM_DATA_OMAP3_IVA_H__
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include <plat/omap_hwmod.h>
+
+/**
+ * hwmod_iva_preprogram - execute reset sequence for IVA2
+ * @oh: pointer to iva2 hwmod
+ *
+ * Runs reset sequence for IVA2. In cases where IVA2 is activated
+ * by bootcode, it may prevent full-chip retention or off-mode
+ * because it is not idle. This function forces the IVA2 into idle
+ * state so it can go into retention/off and thus allow full-chip
+ * retention/off. Always returns 0.
+ */
+static int __maybe_unused hwmod_iva_preprogram(struct omap_hwmod *oh)
+{
+	int i;
+
+	/* Ensure clock is disabled */
+	omap_hwmod_enable_clocks(oh);
+	omap_hwmod_disable_clocks(oh);
+
+	/* Reset IVA2 */
+	for (i = 0; i < oh->rst_lines_cnt; i++)
+		omap_hwmod_assert_hardreset(oh, oh->rst_lines[i].name);
+
+
+	/* Enable IVA2 clock */
+	omap_hwmod_enable_clocks(oh);
+
+	/* Set IVA2 bootmode to 'idle' */
+	omap_ctrl_writel(OMAP3_IVA2_BOOTMOD_IDLE,
+			 OMAP343X_CONTROL_IVA2_BOOTMOD);
+
+	/* Un-reset IVA2 */
+	for (i = 0; i < oh->rst_lines_cnt; i++)
+		omap_hwmod_deassert_hardreset(oh, oh->rst_lines[i].name);
+
+	/* Disable IVA2 clock */
+	omap_hwmod_disable_clocks(oh);
+
+	/* Reset IVA2 */
+	for (i = 0; i < oh->rst_lines_cnt; i++)
+		omap_hwmod_assert_hardreset(oh, oh->rst_lines[i].name);
+
+	return 0;
+}
+
+#endif /* __LINUX_PLATFORM_DATA_OMAP3_IVA_H__ */
-- 
1.7.4.1


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

* [RFC 4/6] ARM: OMAP3: hwmod data: add custom setup_preprogram for iva hwmod
@ 2012-07-13 16:37   ` Tero Kristo
  0 siblings, 0 replies; 30+ messages in thread
From: Tero Kristo @ 2012-07-13 16:37 UTC (permalink / raw)
  To: linux-arm-kernel

IVA2 module must be properly put to idle mode during boot, as it is
possible that it is enabled by bootloader, and this will prevent
core retention/off. Previously this was done by an init time hook
from pm34xx.c file, but this functionality is now moved within
hwmod setup_preprogram hook for iva hwmod.

This patch introduces following warning during boot:

     omap_hwmod: iva: failed to hardreset

This is generated by asserting the 'logic' hardreset for IVA2
hwmod. However, this warning is not fatal, and doesn't cause any
functional problems.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |   13 +++++-
 arch/arm/mach-omap2/pm34xx.c               |   49 -------------------
 include/linux/platform_data/omap3-iva.h    |   73 ++++++++++++++++++++++++++++
 3 files changed, 85 insertions(+), 50 deletions(-)
 create mode 100644 include/linux/platform_data/omap3-iva.h

diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 98bc6f9..1ef6c90 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -14,6 +14,12 @@
  *
  * XXX these should be marked initdata for multi-OMAP kernels
  */
+
+#include <linux/io.h>
+#include "control.h"
+#include "iomap.h"
+#include <linux/platform_data/omap3-iva.h>
+
 #include <plat/omap_hwmod.h>
 #include <mach/irqs.h>
 #include <plat/cpu.h>
@@ -105,9 +111,14 @@ static struct omap_hwmod_rst_info omap3xxx_iva_resets[] = {
 	{ .name = "seq1", .rst_shift = 2, .st_shift = 10 },
 };
 
+static struct omap_hwmod_class omap3xxx_iva_hwmod_class = {
+	.name			= "iva",
+	.setup_preprogram	= hwmod_iva_preprogram,
+};
+
 static struct omap_hwmod omap3xxx_iva_hwmod = {
 	.name		= "iva",
-	.class		= &iva_hwmod_class,
+	.class		= &omap3xxx_iva_hwmod_class,
 	.clkdm_name	= "iva2_clkdm",
 	.rst_lines	= omap3xxx_iva_resets,
 	.rst_lines_cnt	= ARRAY_SIZE(omap3xxx_iva_resets),
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 474ed9d..d407b32 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -333,54 +333,6 @@ restore:
 
 #endif /* CONFIG_SUSPEND */
 
-
-/**
- * omap3_iva_idle(): ensure IVA is in idle so it can be put into
- *                   retention
- *
- * In cases where IVA2 is activated by bootcode, it may prevent
- * full-chip retention or off-mode because it is not idle.  This
- * function forces the IVA2 into idle state so it can go
- * into retention/off and thus allow full-chip retention/off.
- *
- **/
-static void __init omap3_iva_idle(void)
-{
-	/* ensure IVA2 clock is disabled */
-	omap2_cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
-
-	/* if no clock activity, nothing else to do */
-	if (!(omap2_cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSTST) &
-	      OMAP3430_CLKACTIVITY_IVA2_MASK))
-		return;
-
-	/* Reset IVA2 */
-	omap2_prm_write_mod_reg(OMAP3430_RST1_IVA2_MASK |
-			  OMAP3430_RST2_IVA2_MASK |
-			  OMAP3430_RST3_IVA2_MASK,
-			  OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
-
-	/* Enable IVA2 clock */
-	omap2_cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2_MASK,
-			 OMAP3430_IVA2_MOD, CM_FCLKEN);
-
-	/* Set IVA2 boot mode to 'idle' */
-	omap_ctrl_writel(OMAP3_IVA2_BOOTMOD_IDLE,
-			 OMAP343X_CONTROL_IVA2_BOOTMOD);
-
-	/* Un-reset IVA2 */
-	omap2_prm_write_mod_reg(0, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
-
-	/* Disable IVA2 clock */
-	omap2_cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
-
-	/* Reset IVA2 */
-	omap2_prm_write_mod_reg(OMAP3430_RST1_IVA2_MASK |
-			  OMAP3430_RST2_IVA2_MASK |
-			  OMAP3430_RST3_IVA2_MASK,
-			  OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
-}
-
 static void __init omap3_d2d_idle(void)
 {
 	u16 mask, padconf;
@@ -478,7 +430,6 @@ static void __init prcm_setup_regs(void)
 	/* Clear any pending PRCM interrupts */
 	omap2_prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
 
-	omap3_iva_idle();
 	omap3_d2d_idle();
 }
 
diff --git a/include/linux/platform_data/omap3-iva.h b/include/linux/platform_data/omap3-iva.h
new file mode 100644
index 0000000..742349a
--- /dev/null
+++ b/include/linux/platform_data/omap3-iva.h
@@ -0,0 +1,73 @@
+/*
+ * OMAP3 IVA IP block integration
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ * Tero Kristo
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#ifndef __LINUX_PLATFORM_DATA_OMAP3_IVA_H__
+#define __LINUX_PLATFORM_DATA_OMAP3_IVA_H__
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include <plat/omap_hwmod.h>
+
+/**
+ * hwmod_iva_preprogram - execute reset sequence for IVA2
+ * @oh: pointer to iva2 hwmod
+ *
+ * Runs reset sequence for IVA2. In cases where IVA2 is activated
+ * by bootcode, it may prevent full-chip retention or off-mode
+ * because it is not idle. This function forces the IVA2 into idle
+ * state so it can go into retention/off and thus allow full-chip
+ * retention/off. Always returns 0.
+ */
+static int __maybe_unused hwmod_iva_preprogram(struct omap_hwmod *oh)
+{
+	int i;
+
+	/* Ensure clock is disabled */
+	omap_hwmod_enable_clocks(oh);
+	omap_hwmod_disable_clocks(oh);
+
+	/* Reset IVA2 */
+	for (i = 0; i < oh->rst_lines_cnt; i++)
+		omap_hwmod_assert_hardreset(oh, oh->rst_lines[i].name);
+
+
+	/* Enable IVA2 clock */
+	omap_hwmod_enable_clocks(oh);
+
+	/* Set IVA2 bootmode to 'idle' */
+	omap_ctrl_writel(OMAP3_IVA2_BOOTMOD_IDLE,
+			 OMAP343X_CONTROL_IVA2_BOOTMOD);
+
+	/* Un-reset IVA2 */
+	for (i = 0; i < oh->rst_lines_cnt; i++)
+		omap_hwmod_deassert_hardreset(oh, oh->rst_lines[i].name);
+
+	/* Disable IVA2 clock */
+	omap_hwmod_disable_clocks(oh);
+
+	/* Reset IVA2 */
+	for (i = 0; i < oh->rst_lines_cnt; i++)
+		omap_hwmod_assert_hardreset(oh, oh->rst_lines[i].name);
+
+	return 0;
+}
+
+#endif /* __LINUX_PLATFORM_DATA_OMAP3_IVA_H__ */
-- 
1.7.4.1

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

* [RFC 5/6] ARM: OMAP3: hwmod data: add sad2d hwmod
  2012-07-13 16:37 ` Tero Kristo
@ 2012-07-13 16:37   ` Tero Kristo
  -1 siblings, 0 replies; 30+ messages in thread
From: Tero Kristo @ 2012-07-13 16:37 UTC (permalink / raw)
  To: linux-omap, paul, khilman; +Cc: linux-arm-kernel

SAD2D stands for the die to die interface, and is used for communicating
with the optional stacked modem. This hwmod is added in preparation for
the d2d_idle move from pm34xx.c to hwmod data.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/cm-regbits-34xx.h      |    2 +
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |   37 ++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h
index 90d150c8..03b0806 100644
--- a/arch/arm/mach-omap2/cm-regbits-34xx.h
+++ b/arch/arm/mach-omap2/cm-regbits-34xx.h
@@ -218,6 +218,8 @@
 #define OMAP3430_ST_MAILBOXES_MASK			(1 << 7)
 #define OMAP3430_ST_OMAPCTRL_SHIFT			6
 #define OMAP3430_ST_OMAPCTRL_MASK			(1 << 6)
+#define OMAP3430_ST_SAD2D_SHIFT				3
+#define OMAP3430_ST_SAD2D_MASK				(1 << 3)
 #define OMAP3430_ST_SDMA_SHIFT				2
 #define OMAP3430_ST_SDMA_MASK				(1 << 2)
 #define OMAP3430_ST_SDRC_SHIFT				1
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 1ef6c90..dd1335e 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -2017,6 +2017,33 @@ static struct omap_hwmod omap3xxx_hdq1w_hwmod = {
 	.class		= &omap2_hdq1w_class,
 };
 
+/* SAD2D */
+static struct omap_hwmod_rst_info omap3xxx_sad2d_resets[] = {
+	{ .name = "rst_modem_pwron_sw", .rst_shift = 0 },
+	{ .name = "rst_modem_sw", .rst_shift = 1 },
+};
+
+static struct omap_hwmod_class omap3xxx_sad2d_class = {
+	.name			= "sad2d",
+};
+
+static struct omap_hwmod omap3xxx_sad2d_hwmod = {
+	.name		= "sad2d",
+	.rst_lines	= omap3xxx_sad2d_resets,
+	.rst_lines_cnt	= ARRAY_SIZE(omap3xxx_sad2d_resets),
+	.main_clk	= "sad2d_ick",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_SAD2D_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_SAD2D_SHIFT,
+		},
+	},
+	.class		= &omap3xxx_sad2d_class,
+};
+
 /*
  * '32K sync counter' class
  * 32-bit ordinary counter, clocked by the falling edge of the 32 khz clock
@@ -2120,6 +2147,15 @@ static struct omap_hwmod_ocp_if am35xx_usbhsotg__l3 = {
 	.clk		= "core_l3_ick",
 	.user		= OCP_USER_MPU,
 };
+
+/* l3_core -> sad2d interface */
+static struct omap_hwmod_ocp_if omap3xxx_sad2d__l3 = {
+	.master		= &omap3xxx_sad2d_hwmod,
+	.slave		= &omap3xxx_l3_main_hwmod,
+	.clk		= "core_l3_ick",
+	.user		= OCP_USER_MPU,
+};
+
 /* L4_CORE -> L4_WKUP interface */
 static struct omap_hwmod_ocp_if omap3xxx_l4_core__l4_wkup = {
 	.master	= &omap3xxx_l4_core_hwmod,
@@ -3203,6 +3239,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_hwmod_ocp_ifs[] __initdata = {
 	&omap34xx_l4_core__mcspi3,
 	&omap34xx_l4_core__mcspi4,
 	&omap3xxx_l4_wkup__counter_32k,
+	&omap3xxx_sad2d__l3,
 	NULL,
 };
 
-- 
1.7.4.1


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

* [RFC 5/6] ARM: OMAP3: hwmod data: add sad2d hwmod
@ 2012-07-13 16:37   ` Tero Kristo
  0 siblings, 0 replies; 30+ messages in thread
From: Tero Kristo @ 2012-07-13 16:37 UTC (permalink / raw)
  To: linux-arm-kernel

SAD2D stands for the die to die interface, and is used for communicating
with the optional stacked modem. This hwmod is added in preparation for
the d2d_idle move from pm34xx.c to hwmod data.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/cm-regbits-34xx.h      |    2 +
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |   37 ++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h
index 90d150c8..03b0806 100644
--- a/arch/arm/mach-omap2/cm-regbits-34xx.h
+++ b/arch/arm/mach-omap2/cm-regbits-34xx.h
@@ -218,6 +218,8 @@
 #define OMAP3430_ST_MAILBOXES_MASK			(1 << 7)
 #define OMAP3430_ST_OMAPCTRL_SHIFT			6
 #define OMAP3430_ST_OMAPCTRL_MASK			(1 << 6)
+#define OMAP3430_ST_SAD2D_SHIFT				3
+#define OMAP3430_ST_SAD2D_MASK				(1 << 3)
 #define OMAP3430_ST_SDMA_SHIFT				2
 #define OMAP3430_ST_SDMA_MASK				(1 << 2)
 #define OMAP3430_ST_SDRC_SHIFT				1
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 1ef6c90..dd1335e 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -2017,6 +2017,33 @@ static struct omap_hwmod omap3xxx_hdq1w_hwmod = {
 	.class		= &omap2_hdq1w_class,
 };
 
+/* SAD2D */
+static struct omap_hwmod_rst_info omap3xxx_sad2d_resets[] = {
+	{ .name = "rst_modem_pwron_sw", .rst_shift = 0 },
+	{ .name = "rst_modem_sw", .rst_shift = 1 },
+};
+
+static struct omap_hwmod_class omap3xxx_sad2d_class = {
+	.name			= "sad2d",
+};
+
+static struct omap_hwmod omap3xxx_sad2d_hwmod = {
+	.name		= "sad2d",
+	.rst_lines	= omap3xxx_sad2d_resets,
+	.rst_lines_cnt	= ARRAY_SIZE(omap3xxx_sad2d_resets),
+	.main_clk	= "sad2d_ick",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_SAD2D_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_SAD2D_SHIFT,
+		},
+	},
+	.class		= &omap3xxx_sad2d_class,
+};
+
 /*
  * '32K sync counter' class
  * 32-bit ordinary counter, clocked by the falling edge of the 32 khz clock
@@ -2120,6 +2147,15 @@ static struct omap_hwmod_ocp_if am35xx_usbhsotg__l3 = {
 	.clk		= "core_l3_ick",
 	.user		= OCP_USER_MPU,
 };
+
+/* l3_core -> sad2d interface */
+static struct omap_hwmod_ocp_if omap3xxx_sad2d__l3 = {
+	.master		= &omap3xxx_sad2d_hwmod,
+	.slave		= &omap3xxx_l3_main_hwmod,
+	.clk		= "core_l3_ick",
+	.user		= OCP_USER_MPU,
+};
+
 /* L4_CORE -> L4_WKUP interface */
 static struct omap_hwmod_ocp_if omap3xxx_l4_core__l4_wkup = {
 	.master	= &omap3xxx_l4_core_hwmod,
@@ -3203,6 +3239,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_hwmod_ocp_ifs[] __initdata = {
 	&omap34xx_l4_core__mcspi3,
 	&omap34xx_l4_core__mcspi4,
 	&omap3xxx_l4_wkup__counter_32k,
+	&omap3xxx_sad2d__l3,
 	NULL,
 };
 
-- 
1.7.4.1

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

* [RFC 6/6] ARM: OMAP3: hwmod data: add custom setup_preprogram for sad2d hwmod
  2012-07-13 16:37 ` Tero Kristo
@ 2012-07-13 16:37   ` Tero Kristo
  -1 siblings, 0 replies; 30+ messages in thread
From: Tero Kristo @ 2012-07-13 16:37 UTC (permalink / raw)
  To: linux-omap, paul, khilman; +Cc: linux-arm-kernel

SAD2D module must be properly put to idle mode during boot, as if
there is no stacked modem with OMAP3, the pads can be left in a wrong
mode by the bootloader and this can prevent idle. Previously this
was done within pm34xx.c, but the code is now moved to the right
location.

This patch introduces following warning during boot:

     omap_hwmod: sad2d: failed to hardreset

This is generated by asserting the hardresets for SAD2D hwmod, and
is caused by the fuzzy behavior of reset status bits for the module.
This warning is not fatal however and doesn't cause any functional
problems.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |    2 +
 arch/arm/mach-omap2/pm34xx.c               |   26 ------------
 include/linux/platform_data/omap3-d2d.h    |   61 ++++++++++++++++++++++++++++
 3 files changed, 63 insertions(+), 26 deletions(-)
 create mode 100644 include/linux/platform_data/omap3-d2d.h

diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index dd1335e..0a87269 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -19,6 +19,7 @@
 #include "control.h"
 #include "iomap.h"
 #include <linux/platform_data/omap3-iva.h>
+#include <linux/platform_data/omap3-d2d.h>
 
 #include <plat/omap_hwmod.h>
 #include <mach/irqs.h>
@@ -2025,6 +2026,7 @@ static struct omap_hwmod_rst_info omap3xxx_sad2d_resets[] = {
 
 static struct omap_hwmod_class omap3xxx_sad2d_class = {
 	.name			= "sad2d",
+	.setup_preprogram	= hwmod_sad2d_preprogram,
 };
 
 static struct omap_hwmod omap3xxx_sad2d_hwmod = {
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index d407b32..f987c0d 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -333,30 +333,6 @@ restore:
 
 #endif /* CONFIG_SUSPEND */
 
-static void __init omap3_d2d_idle(void)
-{
-	u16 mask, padconf;
-
-	/* In a stand alone OMAP3430 where there is not a stacked
-	 * modem for the D2D Idle Ack and D2D MStandby must be pulled
-	 * high. S CONTROL_PADCONF_SAD2D_IDLEACK and
-	 * CONTROL_PADCONF_SAD2D_MSTDBY to have a pull up. */
-	mask = (1 << 4) | (1 << 3); /* pull-up, enabled */
-	padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_MSTANDBY);
-	padconf |= mask;
-	omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_MSTANDBY);
-
-	padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_IDLEACK);
-	padconf |= mask;
-	omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_IDLEACK);
-
-	/* reset modem */
-	omap2_prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON_MASK |
-			  OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST_MASK,
-			  CORE_MOD, OMAP2_RM_RSTCTRL);
-	omap2_prm_write_mod_reg(0, CORE_MOD, OMAP2_RM_RSTCTRL);
-}
-
 static void __init prcm_setup_regs(void)
 {
 	u32 omap3630_en_uart4_mask = cpu_is_omap3630() ?
@@ -429,8 +405,6 @@ static void __init prcm_setup_regs(void)
 
 	/* Clear any pending PRCM interrupts */
 	omap2_prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
-
-	omap3_d2d_idle();
 }
 
 void omap3_pm_off_mode_enable(int enable)
diff --git a/include/linux/platform_data/omap3-d2d.h b/include/linux/platform_data/omap3-d2d.h
new file mode 100644
index 0000000..d8b44bb
--- /dev/null
+++ b/include/linux/platform_data/omap3-d2d.h
@@ -0,0 +1,61 @@
+/*
+ * OMAP3 Die 2 Die IP block integration
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ * Tero Kristo
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#ifndef __LINUX_PLATFORM_DATA_OMAP3_D2D_H__
+#define __LINUX_PLATFORM_DATA_OMAP3_D2D_H__
+
+#include <linux/kernel.h>
+
+#include <plat/omap_hwmod.h>
+
+/**
+ * hwmod_sad2d_preprogram - programs pull ups for sad2d interface
+ * @oh: pointer to iva2 hwmod
+ *
+ * In a stand alone OMAP3430 chip without a stacked modem, the D2D
+ * Idle Ack and D2D MStandy pads must be pulled
+ * high. So program CONTROL_PADCONF_SAD2D_IDLEACK and
+ * CONTROL_PADCONF_SAD2D_MSTDBY to have a pull up. Always returns 0.
+ */
+static int __maybe_unused hwmod_sad2d_preprogram(struct omap_hwmod *oh)
+{
+	u16 mask, padconf;
+	int i;
+
+	mask = (1 << 4) | (1 << 3); /* pull-up, enabled */
+	padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_MSTANDBY);
+	padconf |= mask;
+	omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_MSTANDBY);
+
+	padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_IDLEACK);
+	padconf |= mask;
+	omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_IDLEACK);
+
+	/* reset modem */
+	for (i = 0; i < oh->rst_lines_cnt; i++)
+		omap_hwmod_assert_hardreset(oh, oh->rst_lines[i].name);
+
+	for (i = 0; i < oh->rst_lines_cnt; i++)
+		omap_hwmod_deassert_hardreset(oh, oh->rst_lines[i].name);
+
+	return 0;
+}
+
+#endif /* __LINUX_PLATFORM_DATA_OMAP3_D2D_H__ */
-- 
1.7.4.1


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

* [RFC 6/6] ARM: OMAP3: hwmod data: add custom setup_preprogram for sad2d hwmod
@ 2012-07-13 16:37   ` Tero Kristo
  0 siblings, 0 replies; 30+ messages in thread
From: Tero Kristo @ 2012-07-13 16:37 UTC (permalink / raw)
  To: linux-arm-kernel

SAD2D module must be properly put to idle mode during boot, as if
there is no stacked modem with OMAP3, the pads can be left in a wrong
mode by the bootloader and this can prevent idle. Previously this
was done within pm34xx.c, but the code is now moved to the right
location.

This patch introduces following warning during boot:

     omap_hwmod: sad2d: failed to hardreset

This is generated by asserting the hardresets for SAD2D hwmod, and
is caused by the fuzzy behavior of reset status bits for the module.
This warning is not fatal however and doesn't cause any functional
problems.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |    2 +
 arch/arm/mach-omap2/pm34xx.c               |   26 ------------
 include/linux/platform_data/omap3-d2d.h    |   61 ++++++++++++++++++++++++++++
 3 files changed, 63 insertions(+), 26 deletions(-)
 create mode 100644 include/linux/platform_data/omap3-d2d.h

diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index dd1335e..0a87269 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -19,6 +19,7 @@
 #include "control.h"
 #include "iomap.h"
 #include <linux/platform_data/omap3-iva.h>
+#include <linux/platform_data/omap3-d2d.h>
 
 #include <plat/omap_hwmod.h>
 #include <mach/irqs.h>
@@ -2025,6 +2026,7 @@ static struct omap_hwmod_rst_info omap3xxx_sad2d_resets[] = {
 
 static struct omap_hwmod_class omap3xxx_sad2d_class = {
 	.name			= "sad2d",
+	.setup_preprogram	= hwmod_sad2d_preprogram,
 };
 
 static struct omap_hwmod omap3xxx_sad2d_hwmod = {
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index d407b32..f987c0d 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -333,30 +333,6 @@ restore:
 
 #endif /* CONFIG_SUSPEND */
 
-static void __init omap3_d2d_idle(void)
-{
-	u16 mask, padconf;
-
-	/* In a stand alone OMAP3430 where there is not a stacked
-	 * modem for the D2D Idle Ack and D2D MStandby must be pulled
-	 * high. S CONTROL_PADCONF_SAD2D_IDLEACK and
-	 * CONTROL_PADCONF_SAD2D_MSTDBY to have a pull up. */
-	mask = (1 << 4) | (1 << 3); /* pull-up, enabled */
-	padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_MSTANDBY);
-	padconf |= mask;
-	omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_MSTANDBY);
-
-	padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_IDLEACK);
-	padconf |= mask;
-	omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_IDLEACK);
-
-	/* reset modem */
-	omap2_prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON_MASK |
-			  OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST_MASK,
-			  CORE_MOD, OMAP2_RM_RSTCTRL);
-	omap2_prm_write_mod_reg(0, CORE_MOD, OMAP2_RM_RSTCTRL);
-}
-
 static void __init prcm_setup_regs(void)
 {
 	u32 omap3630_en_uart4_mask = cpu_is_omap3630() ?
@@ -429,8 +405,6 @@ static void __init prcm_setup_regs(void)
 
 	/* Clear any pending PRCM interrupts */
 	omap2_prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
-
-	omap3_d2d_idle();
 }
 
 void omap3_pm_off_mode_enable(int enable)
diff --git a/include/linux/platform_data/omap3-d2d.h b/include/linux/platform_data/omap3-d2d.h
new file mode 100644
index 0000000..d8b44bb
--- /dev/null
+++ b/include/linux/platform_data/omap3-d2d.h
@@ -0,0 +1,61 @@
+/*
+ * OMAP3 Die 2 Die IP block integration
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ * Tero Kristo
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#ifndef __LINUX_PLATFORM_DATA_OMAP3_D2D_H__
+#define __LINUX_PLATFORM_DATA_OMAP3_D2D_H__
+
+#include <linux/kernel.h>
+
+#include <plat/omap_hwmod.h>
+
+/**
+ * hwmod_sad2d_preprogram - programs pull ups for sad2d interface
+ * @oh: pointer to iva2 hwmod
+ *
+ * In a stand alone OMAP3430 chip without a stacked modem, the D2D
+ * Idle Ack and D2D MStandy pads must be pulled
+ * high. So program CONTROL_PADCONF_SAD2D_IDLEACK and
+ * CONTROL_PADCONF_SAD2D_MSTDBY to have a pull up. Always returns 0.
+ */
+static int __maybe_unused hwmod_sad2d_preprogram(struct omap_hwmod *oh)
+{
+	u16 mask, padconf;
+	int i;
+
+	mask = (1 << 4) | (1 << 3); /* pull-up, enabled */
+	padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_MSTANDBY);
+	padconf |= mask;
+	omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_MSTANDBY);
+
+	padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_IDLEACK);
+	padconf |= mask;
+	omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_IDLEACK);
+
+	/* reset modem */
+	for (i = 0; i < oh->rst_lines_cnt; i++)
+		omap_hwmod_assert_hardreset(oh, oh->rst_lines[i].name);
+
+	for (i = 0; i < oh->rst_lines_cnt; i++)
+		omap_hwmod_deassert_hardreset(oh, oh->rst_lines[i].name);
+
+	return 0;
+}
+
+#endif /* __LINUX_PLATFORM_DATA_OMAP3_D2D_H__ */
-- 
1.7.4.1

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

* Re: [RFC 3/6] ARM: OMAP3: hwmod data: fix iva2 reset info
  2012-07-13 16:37   ` Tero Kristo
@ 2012-07-16  0:12     ` Paul Walmsley
  -1 siblings, 0 replies; 30+ messages in thread
From: Paul Walmsley @ 2012-07-16  0:12 UTC (permalink / raw)
  To: Tero Kristo; +Cc: linux-omap, khilman, linux-arm-kernel

On Fri, 13 Jul 2012, Tero Kristo wrote:

> IVA2 hwmod resets were missing the status bit offsets. Also, as the
> hwmod itself didn't have prcm info at all, resetting iva hwmod was
> accessing some bogus memory addresses. Added both infos to fix this.
>
> Signed-off-by: Tero Kristo <t-kristo@ti.com>

Thanks, this one looks like it's fodder for the -rc series due to the 
accesses, so, queuing for 3.6-rc.


- Paul

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

* [RFC 3/6] ARM: OMAP3: hwmod data: fix iva2 reset info
@ 2012-07-16  0:12     ` Paul Walmsley
  0 siblings, 0 replies; 30+ messages in thread
From: Paul Walmsley @ 2012-07-16  0:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, 13 Jul 2012, Tero Kristo wrote:

> IVA2 hwmod resets were missing the status bit offsets. Also, as the
> hwmod itself didn't have prcm info at all, resetting iva hwmod was
> accessing some bogus memory addresses. Added both infos to fix this.
>
> Signed-off-by: Tero Kristo <t-kristo@ti.com>

Thanks, this one looks like it's fodder for the -rc series due to the 
accesses, so, queuing for 3.6-rc.


- Paul

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

* Re: [RFC 5/6] ARM: OMAP3: hwmod data: add sad2d hwmod
  2012-07-13 16:37   ` Tero Kristo
@ 2012-07-16  1:14     ` Paul Walmsley
  -1 siblings, 0 replies; 30+ messages in thread
From: Paul Walmsley @ 2012-07-16  1:14 UTC (permalink / raw)
  To: Tero Kristo; +Cc: linux-omap, khilman, linux-arm-kernel

On Fri, 13 Jul 2012, Tero Kristo wrote:

> SAD2D stands for the die to die interface, and is used for communicating
> with the optional stacked modem. This hwmod is added in preparation for
> the d2d_idle move from pm34xx.c to hwmod data.
> 
> Signed-off-by: Tero Kristo <t-kristo@ti.com>

Thanks, queued this for 3.7.


- Paul

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

* [RFC 5/6] ARM: OMAP3: hwmod data: add sad2d hwmod
@ 2012-07-16  1:14     ` Paul Walmsley
  0 siblings, 0 replies; 30+ messages in thread
From: Paul Walmsley @ 2012-07-16  1:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, 13 Jul 2012, Tero Kristo wrote:

> SAD2D stands for the die to die interface, and is used for communicating
> with the optional stacked modem. This hwmod is added in preparation for
> the d2d_idle move from pm34xx.c to hwmod data.
> 
> Signed-off-by: Tero Kristo <t-kristo@ti.com>

Thanks, queued this for 3.7.


- Paul

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

* Re: [RFC 5/6] ARM: OMAP3: hwmod data: add sad2d hwmod
  2012-07-13 16:37   ` Tero Kristo
@ 2012-07-16  1:28     ` Paul Walmsley
  -1 siblings, 0 replies; 30+ messages in thread
From: Paul Walmsley @ 2012-07-16  1:28 UTC (permalink / raw)
  To: Tero Kristo; +Cc: linux-omap, khilman, linux-arm-kernel

Hi

One comment

On Fri, 13 Jul 2012, Tero Kristo wrote:

> @@ -3203,6 +3239,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_hwmod_ocp_ifs[] __initdata = {
>  	&omap34xx_l4_core__mcspi3,
>  	&omap34xx_l4_core__mcspi4,
>  	&omap3xxx_l4_wkup__counter_32k,
> +	&omap3xxx_sad2d__l3,
>  	NULL,

This part of the patch doesn't seem right.  As far as I know, AM35xx 
doesn't support the D2D interface.  So it wouldn't make sense to add this 
to the OMAP3-common list.  So instead the patch has been updated here to 
add this to the OMAP34xx and OMAP36xx lists.

Updated patch below.


- Paul

From: Tero Kristo <t-kristo@ti.com>
Date: Fri, 13 Jul 2012 19:37:38 +0300
Subject: [PATCH] ARM: OMAP3: hwmod data: add sad2d hwmod

SAD2D stands for the die to die interface, and is used for communicating
with the optional stacked modem. This hwmod is added in preparation for
the d2d_idle move from pm34xx.c to hwmod data.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
[paul@pwsan.com: SAD2D presumably doesn't exist on non-OMAP34xx/OMAP36xx,
 so only add it to the OMAP34xx/OMAP36xx lists]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
 arch/arm/mach-omap2/cm-regbits-34xx.h      |    2 ++
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |   37 ++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h
index 975f6bd..59598ff 100644
--- a/arch/arm/mach-omap2/cm-regbits-34xx.h
+++ b/arch/arm/mach-omap2/cm-regbits-34xx.h
@@ -218,6 +218,8 @@
 #define OMAP3430_ST_MAILBOXES_MASK			(1 << 7)
 #define OMAP3430_ST_OMAPCTRL_SHIFT			6
 #define OMAP3430_ST_OMAPCTRL_MASK			(1 << 6)
+#define OMAP3430_ST_SAD2D_SHIFT				3
+#define OMAP3430_ST_SAD2D_MASK				(1 << 3)
 #define OMAP3430_ST_SDMA_SHIFT				2
 #define OMAP3430_ST_SDMA_MASK				(1 << 2)
 #define OMAP3430_ST_SDRC_SHIFT				1
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index ce7e606..0dce77e 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -2033,6 +2033,33 @@ static struct omap_hwmod omap3xxx_hdq1w_hwmod = {
 	.class		= &omap2_hdq1w_class,
 };
 
+/* SAD2D */
+static struct omap_hwmod_rst_info omap3xxx_sad2d_resets[] = {
+	{ .name = "rst_modem_pwron_sw", .rst_shift = 0 },
+	{ .name = "rst_modem_sw", .rst_shift = 1 },
+};
+
+static struct omap_hwmod_class omap3xxx_sad2d_class = {
+	.name			= "sad2d",
+};
+
+static struct omap_hwmod omap3xxx_sad2d_hwmod = {
+	.name		= "sad2d",
+	.rst_lines	= omap3xxx_sad2d_resets,
+	.rst_lines_cnt	= ARRAY_SIZE(omap3xxx_sad2d_resets),
+	.main_clk	= "sad2d_ick",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_SAD2D_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_SAD2D_SHIFT,
+		},
+	},
+	.class		= &omap3xxx_sad2d_class,
+};
+
 /*
  * '32K sync counter' class
  * 32-bit ordinary counter, clocked by the falling edge of the 32 khz clock
@@ -2137,6 +2164,14 @@ static struct omap_hwmod_ocp_if am35xx_usbhsotg__l3 = {
 	.user		= OCP_USER_MPU,
 };
 
+/* l3_core -> sad2d interface */
+static struct omap_hwmod_ocp_if omap3xxx_sad2d__l3 = {
+	.master		= &omap3xxx_sad2d_hwmod,
+	.slave		= &omap3xxx_l3_main_hwmod,
+	.clk		= "core_l3_ick",
+	.user		= OCP_USER_MPU,
+};
+
 /* L4_CORE -> L4_WKUP interface */
 static struct omap_hwmod_ocp_if omap3xxx_l4_core__l4_wkup = {
 	.master	= &omap3xxx_l4_core_hwmod,
@@ -3371,6 +3406,7 @@ static struct omap_hwmod_ocp_if *omap34xx_hwmod_ocp_ifs[] __initdata = {
 	&omap34xx_l4_core__sr2,
 	&omap3xxx_l4_core__mailbox,
 	&omap3xxx_l4_core__hdq1w,
+	&omap3xxx_sad2d__l3,
 	NULL
 };
 
@@ -3391,6 +3427,7 @@ static struct omap_hwmod_ocp_if *omap36xx_hwmod_ocp_ifs[] __initdata = {
 	&omap3xxx_l4_core__es3plus_mmc1,
 	&omap3xxx_l4_core__es3plus_mmc2,
 	&omap3xxx_l4_core__hdq1w,
+	&omap3xxx_sad2d__l3,
 	NULL
 };
 
-- 
1.7.10.4


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

* [RFC 5/6] ARM: OMAP3: hwmod data: add sad2d hwmod
@ 2012-07-16  1:28     ` Paul Walmsley
  0 siblings, 0 replies; 30+ messages in thread
From: Paul Walmsley @ 2012-07-16  1:28 UTC (permalink / raw)
  To: linux-arm-kernel

Hi

One comment

On Fri, 13 Jul 2012, Tero Kristo wrote:

> @@ -3203,6 +3239,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_hwmod_ocp_ifs[] __initdata = {
>  	&omap34xx_l4_core__mcspi3,
>  	&omap34xx_l4_core__mcspi4,
>  	&omap3xxx_l4_wkup__counter_32k,
> +	&omap3xxx_sad2d__l3,
>  	NULL,

This part of the patch doesn't seem right.  As far as I know, AM35xx 
doesn't support the D2D interface.  So it wouldn't make sense to add this 
to the OMAP3-common list.  So instead the patch has been updated here to 
add this to the OMAP34xx and OMAP36xx lists.

Updated patch below.


- Paul

From: Tero Kristo <t-kristo@ti.com>
Date: Fri, 13 Jul 2012 19:37:38 +0300
Subject: [PATCH] ARM: OMAP3: hwmod data: add sad2d hwmod

SAD2D stands for the die to die interface, and is used for communicating
with the optional stacked modem. This hwmod is added in preparation for
the d2d_idle move from pm34xx.c to hwmod data.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
[paul at pwsan.com: SAD2D presumably doesn't exist on non-OMAP34xx/OMAP36xx,
 so only add it to the OMAP34xx/OMAP36xx lists]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
 arch/arm/mach-omap2/cm-regbits-34xx.h      |    2 ++
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |   37 ++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h
index 975f6bd..59598ff 100644
--- a/arch/arm/mach-omap2/cm-regbits-34xx.h
+++ b/arch/arm/mach-omap2/cm-regbits-34xx.h
@@ -218,6 +218,8 @@
 #define OMAP3430_ST_MAILBOXES_MASK			(1 << 7)
 #define OMAP3430_ST_OMAPCTRL_SHIFT			6
 #define OMAP3430_ST_OMAPCTRL_MASK			(1 << 6)
+#define OMAP3430_ST_SAD2D_SHIFT				3
+#define OMAP3430_ST_SAD2D_MASK				(1 << 3)
 #define OMAP3430_ST_SDMA_SHIFT				2
 #define OMAP3430_ST_SDMA_MASK				(1 << 2)
 #define OMAP3430_ST_SDRC_SHIFT				1
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index ce7e606..0dce77e 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -2033,6 +2033,33 @@ static struct omap_hwmod omap3xxx_hdq1w_hwmod = {
 	.class		= &omap2_hdq1w_class,
 };
 
+/* SAD2D */
+static struct omap_hwmod_rst_info omap3xxx_sad2d_resets[] = {
+	{ .name = "rst_modem_pwron_sw", .rst_shift = 0 },
+	{ .name = "rst_modem_sw", .rst_shift = 1 },
+};
+
+static struct omap_hwmod_class omap3xxx_sad2d_class = {
+	.name			= "sad2d",
+};
+
+static struct omap_hwmod omap3xxx_sad2d_hwmod = {
+	.name		= "sad2d",
+	.rst_lines	= omap3xxx_sad2d_resets,
+	.rst_lines_cnt	= ARRAY_SIZE(omap3xxx_sad2d_resets),
+	.main_clk	= "sad2d_ick",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_SAD2D_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_SAD2D_SHIFT,
+		},
+	},
+	.class		= &omap3xxx_sad2d_class,
+};
+
 /*
  * '32K sync counter' class
  * 32-bit ordinary counter, clocked by the falling edge of the 32 khz clock
@@ -2137,6 +2164,14 @@ static struct omap_hwmod_ocp_if am35xx_usbhsotg__l3 = {
 	.user		= OCP_USER_MPU,
 };
 
+/* l3_core -> sad2d interface */
+static struct omap_hwmod_ocp_if omap3xxx_sad2d__l3 = {
+	.master		= &omap3xxx_sad2d_hwmod,
+	.slave		= &omap3xxx_l3_main_hwmod,
+	.clk		= "core_l3_ick",
+	.user		= OCP_USER_MPU,
+};
+
 /* L4_CORE -> L4_WKUP interface */
 static struct omap_hwmod_ocp_if omap3xxx_l4_core__l4_wkup = {
 	.master	= &omap3xxx_l4_core_hwmod,
@@ -3371,6 +3406,7 @@ static struct omap_hwmod_ocp_if *omap34xx_hwmod_ocp_ifs[] __initdata = {
 	&omap34xx_l4_core__sr2,
 	&omap3xxx_l4_core__mailbox,
 	&omap3xxx_l4_core__hdq1w,
+	&omap3xxx_sad2d__l3,
 	NULL
 };
 
@@ -3391,6 +3427,7 @@ static struct omap_hwmod_ocp_if *omap36xx_hwmod_ocp_ifs[] __initdata = {
 	&omap3xxx_l4_core__es3plus_mmc1,
 	&omap3xxx_l4_core__es3plus_mmc2,
 	&omap3xxx_l4_core__hdq1w,
+	&omap3xxx_sad2d__l3,
 	NULL
 };
 
-- 
1.7.10.4

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

* Re: [RFC 1/6] ARM: OMAP3: PRM: move prcm interrupt handlers to PRM driver code
  2012-07-13 16:37   ` Tero Kristo
@ 2012-07-16 11:26     ` Rajendra Nayak
  -1 siblings, 0 replies; 30+ messages in thread
From: Rajendra Nayak @ 2012-07-16 11:26 UTC (permalink / raw)
  To: Tero Kristo; +Cc: linux-omap, paul, khilman, linux-arm-kernel

On Friday 13 July 2012 10:07 PM, Tero Kristo wrote:
> PM code doesn't really care about the PRCM wakeup + io interrupts on
> OMAP3, as these are used only for acking PRCM internal events, and the
> IO chain handler is taken care of by hwmod code. Thus move the interrupt
> handling logic from pm34xx.c to prm2xxx_3xxx.c file. This patch also
> includes a minor cleanup for removing the priority handling and replacing
> it with a mechanism for acking pending events. This gets rid of the need
> for registering the shared interrupt handlers in specific order.

It would be easier to review if you were to split this into 2 patches,
one which moves functions around as-is and another which does the
cleanup/optimization. Having both in one is kinda hard to review.

>
> Signed-off-by: Tero Kristo<t-kristo@ti.com>
> ---
>   arch/arm/mach-omap2/pm34xx.c       |  109 +------------------------------
>   arch/arm/mach-omap2/prcm-common.h  |   10 ++--
>   arch/arm/mach-omap2/prm2xxx_3xxx.c |  124 ++++++++++++++++++++++++++++++++++--
>   arch/arm/mach-omap2/prm2xxx_3xxx.h |    1 +
>   arch/arm/mach-omap2/prm44xx.c      |    4 +-
>   arch/arm/mach-omap2/prm_common.c   |   42 ++----------
>   6 files changed, 138 insertions(+), 152 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
> index d25a9d8..474ed9d 100644
> --- a/arch/arm/mach-omap2/pm34xx.c
> +++ b/arch/arm/mach-omap2/pm34xx.c
> @@ -133,85 +133,6 @@ static void omap3_save_secure_ram_context(void)
>   	}
>   }
>
> -/*
> - * PRCM Interrupt Handler Helper Function
> - *
> - * The purpose of this function is to clear any wake-up events latched
> - * in the PRCM PM_WKST_x registers. It is possible that a wake-up event
> - * may occur whilst attempting to clear a PM_WKST_x register and thus
> - * set another bit in this register. A while loop is used to ensure
> - * that any peripheral wake-up events occurring while attempting to
> - * clear the PM_WKST_x are detected and cleared.
> - */
> -static int prcm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits)
> -{
> -	u32 wkst, fclk, iclk, clken;
> -	u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
> -	u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1;
> -	u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1;
> -	u16 grpsel_off = (regs == 3) ?
> -		OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL;
> -	int c = 0;
> -
> -	wkst = omap2_prm_read_mod_reg(module, wkst_off);
> -	wkst&= omap2_prm_read_mod_reg(module, grpsel_off);
> -	wkst&= ~ignore_bits;
> -	if (wkst) {
> -		iclk = omap2_cm_read_mod_reg(module, iclk_off);
> -		fclk = omap2_cm_read_mod_reg(module, fclk_off);
> -		while (wkst) {
> -			clken = wkst;
> -			omap2_cm_set_mod_reg_bits(clken, module, iclk_off);
> -			/*
> -			 * For USBHOST, we don't know whether HOST1 or
> -			 * HOST2 woke us up, so enable both f-clocks
> -			 */
> -			if (module == OMAP3430ES2_USBHOST_MOD)
> -				clken |= 1<<  OMAP3430ES2_EN_USBHOST2_SHIFT;
> -			omap2_cm_set_mod_reg_bits(clken, module, fclk_off);
> -			omap2_prm_write_mod_reg(wkst, module, wkst_off);
> -			wkst = omap2_prm_read_mod_reg(module, wkst_off);
> -			wkst&= ~ignore_bits;
> -			c++;
> -		}
> -		omap2_cm_write_mod_reg(iclk, module, iclk_off);
> -		omap2_cm_write_mod_reg(fclk, module, fclk_off);
> -	}
> -
> -	return c;
> -}
> -
> -static irqreturn_t _prcm_int_handle_io(int irq, void *unused)
> -{
> -	int c;
> -
> -	c = prcm_clear_mod_irqs(WKUP_MOD, 1,
> -		~(OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK));
> -
> -	return c ? IRQ_HANDLED : IRQ_NONE;
> -}
> -
> -static irqreturn_t _prcm_int_handle_wakeup(int irq, void *unused)
> -{
> -	int c;
> -
> -	/*
> -	 * Clear all except ST_IO and ST_IO_CHAIN for wkup module,
> -	 * these are handled in a separate handler to avoid acking
> -	 * IO events before parsing in mux code
> -	 */
> -	c = prcm_clear_mod_irqs(WKUP_MOD, 1,
> -		OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK);
> -	c += prcm_clear_mod_irqs(CORE_MOD, 1, 0);
> -	c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1, 0);
> -	if (omap_rev()>  OMAP3430_REV_ES1_0) {
> -		c += prcm_clear_mod_irqs(CORE_MOD, 3, 0);
> -		c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1, 0);
> -	}
> -
> -	return c ? IRQ_HANDLED : IRQ_NONE;
> -}
> -
>   static void omap34xx_save_context(u32 *save)
>   {
>   	u32 val;
> @@ -671,29 +592,10 @@ int __init omap3_pm_init(void)
>   	 * supervised mode for powerdomains */
>   	prcm_setup_regs();
>
> -	ret = request_irq(omap_prcm_event_to_irq("wkup"),
> -		_prcm_int_handle_wakeup, IRQF_NO_SUSPEND, "pm_wkup", NULL);
> -
> -	if (ret) {
> -		pr_err("pm: Failed to request pm_wkup irq\n");
> -		goto err1;
> -	}
> -
> -	/* IO interrupt is shared with mux code */
> -	ret = request_irq(omap_prcm_event_to_irq("io"),
> -		_prcm_int_handle_io, IRQF_SHARED | IRQF_NO_SUSPEND, "pm_io",
> -		omap3_pm_init);
> -	enable_irq(omap_prcm_event_to_irq("io"));
> -
> -	if (ret) {
> -		pr_err("pm: Failed to request pm_io irq\n");
> -		goto err2;
> -	}
> -
>   	ret = pwrdm_for_each(pwrdms_setup, NULL);
>   	if (ret) {
>   		pr_err("Failed to setup powerdomains\n");
> -		goto err3;
> +		goto err;
>   	}
>
>   	(void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
> @@ -702,7 +604,7 @@ int __init omap3_pm_init(void)
>   	if (mpu_pwrdm == NULL) {
>   		pr_err("Failed to get mpu_pwrdm\n");
>   		ret = -EINVAL;
> -		goto err3;
> +		goto err;
>   	}
>
>   	neon_pwrdm = pwrdm_lookup("neon_pwrdm");
> @@ -750,14 +652,11 @@ int __init omap3_pm_init(void)
>   	omap3_save_scratchpad_contents();
>   	return ret;
>
> -err3:
> +err:
>   	list_for_each_entry_safe(pwrst, tmp,&pwrst_list, node) {
>   		list_del(&pwrst->node);
>   		kfree(pwrst);
>   	}
> -	free_irq(omap_prcm_event_to_irq("io"), omap3_pm_init);
> -err2:
> -	free_irq(omap_prcm_event_to_irq("wkup"), NULL);
> -err1:
> +
>   	return ret;
>   }
> diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
> index fca23cb..ad23bb4 100644
> --- a/arch/arm/mach-omap2/prcm-common.h
> +++ b/arch/arm/mach-omap2/prcm-common.h
> @@ -466,6 +466,7 @@ struct omap_prcm_irq {
>    * @ocp_barrier: fn ptr to force buffered PRM writes to complete
>    * @save_and_clear_irqen: fn ptr to save and clear IRQENABLE regs
>    * @restore_irqen: fn ptr to save and clear IRQENABLE regs
> + * @ack_pending_events: fn ptr to ack pending events after handling
>    * @saved_mask: IRQENABLE regs are saved here during suspend
>    * @priority_mask: 1 bit per IRQ, set to 1 if omap_prcm_irq.priority = true
>    * @base_irq: base dynamic IRQ number, returned from irq_alloc_descs() in init
> @@ -487,18 +488,17 @@ struct omap_prcm_irq_setup {
>   	void (*ocp_barrier)(void);
>   	void (*save_and_clear_irqen)(u32 *saved_mask);
>   	void (*restore_irqen)(u32 *saved_mask);
> +	void (*ack_pending_events)(unsigned long *events);
>   	u32 *saved_mask;
> -	u32 *priority_mask;
>   	int base_irq;
>   	bool suspended;
>   	bool suspend_save_flag;
>   };
>
>   /* OMAP_PRCM_IRQ: convenience macro for creating struct omap_prcm_irq records */
> -#define OMAP_PRCM_IRQ(_name, _offset, _priority) {	\
> -	.name = _name,					\
> -	.offset = _offset,				\
> -	.priority = _priority				\
> +#define OMAP_PRCM_IRQ(_name, _offset) {	\
> +	.name = _name,			\
> +	.offset = _offset,		\
>   	}
>
>   extern void omap_prcm_irq_cleanup(void);
> diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
> index a0309de..3761019 100644
> --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
> +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
> @@ -16,6 +16,7 @@
>   #include<linux/err.h>
>   #include<linux/io.h>
>   #include<linux/irq.h>
> +#include<linux/interrupt.h>
>
>   #include "common.h"
>   #include<plat/cpu.h>
> @@ -28,10 +29,11 @@
>   #include "cm2xxx_3xxx.h"
>   #include "prm-regbits-24xx.h"
>   #include "prm-regbits-34xx.h"
> +#include "cm-regbits-34xx.h"
>
>   static const struct omap_prcm_irq omap3_prcm_irqs[] = {
> -	OMAP_PRCM_IRQ("wkup",	0,	0),
> -	OMAP_PRCM_IRQ("io",	9,	1),
> +	OMAP_PRCM_IRQ("wkup",	0),
> +	OMAP_PRCM_IRQ("io",	9),
>   };
>
>   static struct omap_prcm_irq_setup omap3_prcm_irq_setup = {
> @@ -45,6 +47,7 @@ static struct omap_prcm_irq_setup omap3_prcm_irq_setup = {
>   	.ocp_barrier		=&omap3xxx_prm_ocp_barrier,
>   	.save_and_clear_irqen	=&omap3xxx_prm_save_and_clear_irqen,
>   	.restore_irqen		=&omap3xxx_prm_restore_irqen,
> +	.ack_pending_events	=&omap3xxx_prm_clear_wakeups,
>   };
>
>   u32 omap2_prm_read_mod_reg(s16 module, u16 idx)
> @@ -349,18 +352,127 @@ static void __init omap3xxx_prm_enable_io_wakeup(void)
>   					   PM_WKEN);
>   }
>
> +/**
> + * prcm_clear_mod_irqs - clear module level wakeup irqs for omap3
> + * @module: prm module to clear
> + * @regs: register set to use, either 1 or 3
> + *
> + * The purpose of this function is to clear any wake-up events latched
> + * in the PRCM PM_WKST_x registers. It is possible that a wake-up event
> + * may occur whilst attempting to clear a PM_WKST_x register and thus
> + * set another bit in this register. A while loop is used to ensure
> + * that any peripheral wake-up events occurring while attempting to
> + * clear the PM_WKST_x are detected and cleared. Returns the number
> + * of active wakeup events detected, or 0 if none.
> + */
> +static int _prcm_clear_mod_irqs(s16 module, u8 regs)
> +{
> +	u32 wkst, fclk, iclk, clken;
> +	u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
> +	u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1;
> +	u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1;
> +	u16 grpsel_off = (regs == 3) ?
> +		OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL;
> +	int c = 0;
> +
> +	wkst = omap2_prm_read_mod_reg(module, wkst_off);
> +	wkst&= omap2_prm_read_mod_reg(module, grpsel_off);
> +	if (wkst) {
> +		iclk = omap2_cm_read_mod_reg(module, iclk_off);
> +		fclk = omap2_cm_read_mod_reg(module, fclk_off);
> +		while (wkst) {
> +			clken = wkst;
> +			omap2_cm_set_mod_reg_bits(clken, module, iclk_off);
> +			/*
> +			 * For USBHOST, we don't know whether HOST1 or
> +			 * HOST2 woke us up, so enable both f-clocks
> +			 */
> +			if (module == OMAP3430ES2_USBHOST_MOD)
> +				clken |= 1<<  OMAP3430ES2_EN_USBHOST2_SHIFT;
> +			omap2_cm_set_mod_reg_bits(clken, module, fclk_off);
> +			omap2_prm_write_mod_reg(wkst, module, wkst_off);
> +			wkst = omap2_prm_read_mod_reg(module, wkst_off);
> +			c++;
> +		}
> +		omap2_cm_write_mod_reg(iclk, module, iclk_off);
> +		omap2_cm_write_mod_reg(fclk, module, fclk_off);
> +	}
> +
> +	return c;
> +}
> +
> +/**
> + * omap3xxx_prm_clear_wakeups - clears wakeup event sources
> + * @events: active PRCM interrupt event mask
> + *
> + * This function will first check if PRCM chain handler detected
> + * a wakeup event or not. If yes, it will continue to clear any
> + * pending wakeup events from PRCM module. Typically the module
> + * will generate an actual interrupt together with the wakeup event,
> + * which will then be handled separately by the driver code.
> + */
> +void omap3xxx_prm_clear_wakeups(unsigned long *events)
> +{
> +	int c;
> +
> +	/*
> +	 * If we didn't come here because of a wakeup event, do nothing
> +	 */
> +	if (!(events[0]&  OMAP3430_WKUP_ST_MASK))
> +		return;
> +
> +	c = _prcm_clear_mod_irqs(WKUP_MOD, 1);
> +	c += _prcm_clear_mod_irqs(CORE_MOD, 1);
> +	c += _prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1);
> +	if (omap_rev()>  OMAP3430_REV_ES1_0) {
> +		c += _prcm_clear_mod_irqs(CORE_MOD, 3);
> +		c += _prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
> +	}
> +}
> +
> +/**
> + * _prcm_int_handle_wakeup - dummy irq handler for prcm wakeup event
> + * @irq: not used, irq common API
> + * @unused: not used, irq common API
> + *
> + * Dummy handler for PRCM wakeup event interrupt. On software level,
> + * this handler doesn't do anything, but it is needed for hardware
> + * to function properly. Adding this handler will enable the wakeup
> + * event generation from PRCM, which is needed to get CPU out of
> + * WFI. Otherwise the CPU will get stuck on the WFI instruction
> + * indefinitely, as the MPU powerdomain remains idle.
> + */
> +static irqreturn_t _prcm_int_handle_wakeup(int irq, void *unused)
> +{
> +	return IRQ_HANDLED;
> +}
> +
>   static int __init omap3xxx_prcm_init(void)
>   {
> -	int ret = 0;
> +	int ret;
>
>   	if (cpu_is_omap34xx()) {
>   		omap3xxx_prm_enable_io_wakeup();
>   		ret = omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
> -		if (!ret)
> -			irq_set_status_flags(omap_prcm_event_to_irq("io"),
> -					     IRQ_NOAUTOEN);
> +		if (ret) {
> +			pr_err("%s: failed to register chain handler: %d\n",
> +				__func__, ret);
> +			return ret;
> +		}
> +
> +		ret = request_irq(omap_prcm_event_to_irq("wkup"),
> +			_prcm_int_handle_wakeup, IRQF_NO_SUSPEND, "prcm_wkup",
> +			NULL);
> +		if (ret) {
> +			pr_err("%s: failed to request prcm_wkup irq: %d\n",
> +				__func__, ret);
> +			goto err;
> +		}
>   	}
>
> +	return 0;
> +err:
> +	omap_prcm_irq_cleanup();
>   	return ret;
>   }
>   subsys_initcall(omap3xxx_prcm_init);
> diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h
> index 1ba3d65..078df35 100644
> --- a/arch/arm/mach-omap2/prm2xxx_3xxx.h
> +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h
> @@ -322,6 +322,7 @@ extern void omap3xxx_prm_read_pending_irqs(unsigned long *events);
>   extern void omap3xxx_prm_ocp_barrier(void);
>   extern void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask);
>   extern void omap3xxx_prm_restore_irqen(u32 *saved_mask);
> +extern void omap3xxx_prm_clear_wakeups(unsigned long *events);
>
>   #endif	/* CONFIG_ARCH_OMAP4 */
>
> diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c
> index bb727c2..fd26279 100644
> --- a/arch/arm/mach-omap2/prm44xx.c
> +++ b/arch/arm/mach-omap2/prm44xx.c
> @@ -30,8 +30,8 @@
>   #include "prminst44xx.h"
>
>   static const struct omap_prcm_irq omap4_prcm_irqs[] = {
> -	OMAP_PRCM_IRQ("wkup",   0,      0),
> -	OMAP_PRCM_IRQ("io",     9,      1),
> +	OMAP_PRCM_IRQ("wkup",	0),
> +	OMAP_PRCM_IRQ("io",	9),
>   };
>
>   static struct omap_prcm_irq_setup omap4_prcm_irq_setup = {
> diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c
> index dfe00dd..4643651 100644
> --- a/arch/arm/mach-omap2/prm_common.c
> +++ b/arch/arm/mach-omap2/prm_common.c
> @@ -57,21 +57,6 @@ static struct omap_prcm_irq_setup *prcm_irq_setup;
>   /* Private functions */
>
>   /*
> - * Move priority events from events to priority_events array
> - */
> -static void omap_prcm_events_filter_priority(unsigned long *events,
> -	unsigned long *priority_events)
> -{
> -	int i;
> -
> -	for (i = 0; i<  prcm_irq_setup->nr_regs; i++) {
> -		priority_events[i] =
> -			events[i]&  prcm_irq_setup->priority_mask[i];
> -		events[i] ^= priority_events[i];
> -	}
> -}
> -
> -/*
>    * PRCM Interrupt Handler
>    *
>    * This is a common handler for the OMAP PRCM interrupts. Pending
> @@ -82,7 +67,6 @@ static void omap_prcm_events_filter_priority(unsigned long *events,
>   static void omap_prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
>   {
>   	unsigned long pending[OMAP_PRCM_MAX_NR_PENDING_REG];
> -	unsigned long priority_pending[OMAP_PRCM_MAX_NR_PENDING_REG];
>   	struct irq_chip *chip = irq_desc_get_chip(desc);
>   	unsigned int virtirq;
>   	int nr_irqs = prcm_irq_setup->nr_regs * 32;
> @@ -113,20 +97,19 @@ static void omap_prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
>   		if (find_first_bit(pending, nr_irqs)>= nr_irqs)
>   			break;
>
> -		omap_prcm_events_filter_priority(pending, priority_pending);
> -
>   		/*
>   		 * Loop on all currently pending irqs so that new irqs
>   		 * cannot starve previously pending irqs
>   		 */
> -
> -		/* Serve priority events first */
> -		for_each_set_bit(virtirq, priority_pending, nr_irqs)
> -			generic_handle_irq(prcm_irq_setup->base_irq + virtirq);
> -
> -		/* Serve normal events next */
>   		for_each_set_bit(virtirq, pending, nr_irqs)
>   			generic_handle_irq(prcm_irq_setup->base_irq + virtirq);
> +
> +		/*
> +		 * Ack pending events if needed, this will clean the
> +		 * wakeup events on omap3
> +		 */
> +		if (prcm_irq_setup->ack_pending_events)
> +			prcm_irq_setup->ack_pending_events(pending);
>   	}
>   	if (chip->irq_ack)
>   		chip->irq_ack(&desc->irq_data);
> @@ -191,9 +174,6 @@ void omap_prcm_irq_cleanup(void)
>   	kfree(prcm_irq_setup->saved_mask);
>   	prcm_irq_setup->saved_mask = NULL;
>
> -	kfree(prcm_irq_setup->priority_mask);
> -	prcm_irq_setup->priority_mask = NULL;
> -
>   	irq_set_chained_handler(prcm_irq_setup->irq, NULL);
>
>   	if (prcm_irq_setup->base_irq>  0)
> @@ -262,11 +242,8 @@ int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
>
>   	prcm_irq_chips = kzalloc(sizeof(void *) * nr_regs, GFP_KERNEL);
>   	prcm_irq_setup->saved_mask = kzalloc(sizeof(u32) * nr_regs, GFP_KERNEL);
> -	prcm_irq_setup->priority_mask = kzalloc(sizeof(u32) * nr_regs,
> -		GFP_KERNEL);
>
> -	if (!prcm_irq_chips || !prcm_irq_setup->saved_mask ||
> -	    !prcm_irq_setup->priority_mask) {
> +	if (!prcm_irq_chips || !prcm_irq_setup->saved_mask) {
>   		pr_err("PRCM: kzalloc failed\n");
>   		goto err;
>   	}
> @@ -276,9 +253,6 @@ int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
>   	for (i = 0; i<  irq_setup->nr_irqs; i++) {
>   		offset = irq_setup->irqs[i].offset;
>   		mask[offset>>  5] |= 1<<  (offset&  0x1f);
> -		if (irq_setup->irqs[i].priority)
> -			irq_setup->priority_mask[offset>>  5] |=
> -				1<<  (offset&  0x1f);
>   	}
>
>   	irq_set_chained_handler(irq_setup->irq, omap_prcm_irq_handler);


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

* [RFC 1/6] ARM: OMAP3: PRM: move prcm interrupt handlers to PRM driver code
@ 2012-07-16 11:26     ` Rajendra Nayak
  0 siblings, 0 replies; 30+ messages in thread
From: Rajendra Nayak @ 2012-07-16 11:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 13 July 2012 10:07 PM, Tero Kristo wrote:
> PM code doesn't really care about the PRCM wakeup + io interrupts on
> OMAP3, as these are used only for acking PRCM internal events, and the
> IO chain handler is taken care of by hwmod code. Thus move the interrupt
> handling logic from pm34xx.c to prm2xxx_3xxx.c file. This patch also
> includes a minor cleanup for removing the priority handling and replacing
> it with a mechanism for acking pending events. This gets rid of the need
> for registering the shared interrupt handlers in specific order.

It would be easier to review if you were to split this into 2 patches,
one which moves functions around as-is and another which does the
cleanup/optimization. Having both in one is kinda hard to review.

>
> Signed-off-by: Tero Kristo<t-kristo@ti.com>
> ---
>   arch/arm/mach-omap2/pm34xx.c       |  109 +------------------------------
>   arch/arm/mach-omap2/prcm-common.h  |   10 ++--
>   arch/arm/mach-omap2/prm2xxx_3xxx.c |  124 ++++++++++++++++++++++++++++++++++--
>   arch/arm/mach-omap2/prm2xxx_3xxx.h |    1 +
>   arch/arm/mach-omap2/prm44xx.c      |    4 +-
>   arch/arm/mach-omap2/prm_common.c   |   42 ++----------
>   6 files changed, 138 insertions(+), 152 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
> index d25a9d8..474ed9d 100644
> --- a/arch/arm/mach-omap2/pm34xx.c
> +++ b/arch/arm/mach-omap2/pm34xx.c
> @@ -133,85 +133,6 @@ static void omap3_save_secure_ram_context(void)
>   	}
>   }
>
> -/*
> - * PRCM Interrupt Handler Helper Function
> - *
> - * The purpose of this function is to clear any wake-up events latched
> - * in the PRCM PM_WKST_x registers. It is possible that a wake-up event
> - * may occur whilst attempting to clear a PM_WKST_x register and thus
> - * set another bit in this register. A while loop is used to ensure
> - * that any peripheral wake-up events occurring while attempting to
> - * clear the PM_WKST_x are detected and cleared.
> - */
> -static int prcm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits)
> -{
> -	u32 wkst, fclk, iclk, clken;
> -	u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
> -	u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1;
> -	u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1;
> -	u16 grpsel_off = (regs == 3) ?
> -		OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL;
> -	int c = 0;
> -
> -	wkst = omap2_prm_read_mod_reg(module, wkst_off);
> -	wkst&= omap2_prm_read_mod_reg(module, grpsel_off);
> -	wkst&= ~ignore_bits;
> -	if (wkst) {
> -		iclk = omap2_cm_read_mod_reg(module, iclk_off);
> -		fclk = omap2_cm_read_mod_reg(module, fclk_off);
> -		while (wkst) {
> -			clken = wkst;
> -			omap2_cm_set_mod_reg_bits(clken, module, iclk_off);
> -			/*
> -			 * For USBHOST, we don't know whether HOST1 or
> -			 * HOST2 woke us up, so enable both f-clocks
> -			 */
> -			if (module == OMAP3430ES2_USBHOST_MOD)
> -				clken |= 1<<  OMAP3430ES2_EN_USBHOST2_SHIFT;
> -			omap2_cm_set_mod_reg_bits(clken, module, fclk_off);
> -			omap2_prm_write_mod_reg(wkst, module, wkst_off);
> -			wkst = omap2_prm_read_mod_reg(module, wkst_off);
> -			wkst&= ~ignore_bits;
> -			c++;
> -		}
> -		omap2_cm_write_mod_reg(iclk, module, iclk_off);
> -		omap2_cm_write_mod_reg(fclk, module, fclk_off);
> -	}
> -
> -	return c;
> -}
> -
> -static irqreturn_t _prcm_int_handle_io(int irq, void *unused)
> -{
> -	int c;
> -
> -	c = prcm_clear_mod_irqs(WKUP_MOD, 1,
> -		~(OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK));
> -
> -	return c ? IRQ_HANDLED : IRQ_NONE;
> -}
> -
> -static irqreturn_t _prcm_int_handle_wakeup(int irq, void *unused)
> -{
> -	int c;
> -
> -	/*
> -	 * Clear all except ST_IO and ST_IO_CHAIN for wkup module,
> -	 * these are handled in a separate handler to avoid acking
> -	 * IO events before parsing in mux code
> -	 */
> -	c = prcm_clear_mod_irqs(WKUP_MOD, 1,
> -		OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK);
> -	c += prcm_clear_mod_irqs(CORE_MOD, 1, 0);
> -	c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1, 0);
> -	if (omap_rev()>  OMAP3430_REV_ES1_0) {
> -		c += prcm_clear_mod_irqs(CORE_MOD, 3, 0);
> -		c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1, 0);
> -	}
> -
> -	return c ? IRQ_HANDLED : IRQ_NONE;
> -}
> -
>   static void omap34xx_save_context(u32 *save)
>   {
>   	u32 val;
> @@ -671,29 +592,10 @@ int __init omap3_pm_init(void)
>   	 * supervised mode for powerdomains */
>   	prcm_setup_regs();
>
> -	ret = request_irq(omap_prcm_event_to_irq("wkup"),
> -		_prcm_int_handle_wakeup, IRQF_NO_SUSPEND, "pm_wkup", NULL);
> -
> -	if (ret) {
> -		pr_err("pm: Failed to request pm_wkup irq\n");
> -		goto err1;
> -	}
> -
> -	/* IO interrupt is shared with mux code */
> -	ret = request_irq(omap_prcm_event_to_irq("io"),
> -		_prcm_int_handle_io, IRQF_SHARED | IRQF_NO_SUSPEND, "pm_io",
> -		omap3_pm_init);
> -	enable_irq(omap_prcm_event_to_irq("io"));
> -
> -	if (ret) {
> -		pr_err("pm: Failed to request pm_io irq\n");
> -		goto err2;
> -	}
> -
>   	ret = pwrdm_for_each(pwrdms_setup, NULL);
>   	if (ret) {
>   		pr_err("Failed to setup powerdomains\n");
> -		goto err3;
> +		goto err;
>   	}
>
>   	(void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
> @@ -702,7 +604,7 @@ int __init omap3_pm_init(void)
>   	if (mpu_pwrdm == NULL) {
>   		pr_err("Failed to get mpu_pwrdm\n");
>   		ret = -EINVAL;
> -		goto err3;
> +		goto err;
>   	}
>
>   	neon_pwrdm = pwrdm_lookup("neon_pwrdm");
> @@ -750,14 +652,11 @@ int __init omap3_pm_init(void)
>   	omap3_save_scratchpad_contents();
>   	return ret;
>
> -err3:
> +err:
>   	list_for_each_entry_safe(pwrst, tmp,&pwrst_list, node) {
>   		list_del(&pwrst->node);
>   		kfree(pwrst);
>   	}
> -	free_irq(omap_prcm_event_to_irq("io"), omap3_pm_init);
> -err2:
> -	free_irq(omap_prcm_event_to_irq("wkup"), NULL);
> -err1:
> +
>   	return ret;
>   }
> diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
> index fca23cb..ad23bb4 100644
> --- a/arch/arm/mach-omap2/prcm-common.h
> +++ b/arch/arm/mach-omap2/prcm-common.h
> @@ -466,6 +466,7 @@ struct omap_prcm_irq {
>    * @ocp_barrier: fn ptr to force buffered PRM writes to complete
>    * @save_and_clear_irqen: fn ptr to save and clear IRQENABLE regs
>    * @restore_irqen: fn ptr to save and clear IRQENABLE regs
> + * @ack_pending_events: fn ptr to ack pending events after handling
>    * @saved_mask: IRQENABLE regs are saved here during suspend
>    * @priority_mask: 1 bit per IRQ, set to 1 if omap_prcm_irq.priority = true
>    * @base_irq: base dynamic IRQ number, returned from irq_alloc_descs() in init
> @@ -487,18 +488,17 @@ struct omap_prcm_irq_setup {
>   	void (*ocp_barrier)(void);
>   	void (*save_and_clear_irqen)(u32 *saved_mask);
>   	void (*restore_irqen)(u32 *saved_mask);
> +	void (*ack_pending_events)(unsigned long *events);
>   	u32 *saved_mask;
> -	u32 *priority_mask;
>   	int base_irq;
>   	bool suspended;
>   	bool suspend_save_flag;
>   };
>
>   /* OMAP_PRCM_IRQ: convenience macro for creating struct omap_prcm_irq records */
> -#define OMAP_PRCM_IRQ(_name, _offset, _priority) {	\
> -	.name = _name,					\
> -	.offset = _offset,				\
> -	.priority = _priority				\
> +#define OMAP_PRCM_IRQ(_name, _offset) {	\
> +	.name = _name,			\
> +	.offset = _offset,		\
>   	}
>
>   extern void omap_prcm_irq_cleanup(void);
> diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
> index a0309de..3761019 100644
> --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
> +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
> @@ -16,6 +16,7 @@
>   #include<linux/err.h>
>   #include<linux/io.h>
>   #include<linux/irq.h>
> +#include<linux/interrupt.h>
>
>   #include "common.h"
>   #include<plat/cpu.h>
> @@ -28,10 +29,11 @@
>   #include "cm2xxx_3xxx.h"
>   #include "prm-regbits-24xx.h"
>   #include "prm-regbits-34xx.h"
> +#include "cm-regbits-34xx.h"
>
>   static const struct omap_prcm_irq omap3_prcm_irqs[] = {
> -	OMAP_PRCM_IRQ("wkup",	0,	0),
> -	OMAP_PRCM_IRQ("io",	9,	1),
> +	OMAP_PRCM_IRQ("wkup",	0),
> +	OMAP_PRCM_IRQ("io",	9),
>   };
>
>   static struct omap_prcm_irq_setup omap3_prcm_irq_setup = {
> @@ -45,6 +47,7 @@ static struct omap_prcm_irq_setup omap3_prcm_irq_setup = {
>   	.ocp_barrier		=&omap3xxx_prm_ocp_barrier,
>   	.save_and_clear_irqen	=&omap3xxx_prm_save_and_clear_irqen,
>   	.restore_irqen		=&omap3xxx_prm_restore_irqen,
> +	.ack_pending_events	=&omap3xxx_prm_clear_wakeups,
>   };
>
>   u32 omap2_prm_read_mod_reg(s16 module, u16 idx)
> @@ -349,18 +352,127 @@ static void __init omap3xxx_prm_enable_io_wakeup(void)
>   					   PM_WKEN);
>   }
>
> +/**
> + * prcm_clear_mod_irqs - clear module level wakeup irqs for omap3
> + * @module: prm module to clear
> + * @regs: register set to use, either 1 or 3
> + *
> + * The purpose of this function is to clear any wake-up events latched
> + * in the PRCM PM_WKST_x registers. It is possible that a wake-up event
> + * may occur whilst attempting to clear a PM_WKST_x register and thus
> + * set another bit in this register. A while loop is used to ensure
> + * that any peripheral wake-up events occurring while attempting to
> + * clear the PM_WKST_x are detected and cleared. Returns the number
> + * of active wakeup events detected, or 0 if none.
> + */
> +static int _prcm_clear_mod_irqs(s16 module, u8 regs)
> +{
> +	u32 wkst, fclk, iclk, clken;
> +	u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
> +	u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1;
> +	u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1;
> +	u16 grpsel_off = (regs == 3) ?
> +		OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL;
> +	int c = 0;
> +
> +	wkst = omap2_prm_read_mod_reg(module, wkst_off);
> +	wkst&= omap2_prm_read_mod_reg(module, grpsel_off);
> +	if (wkst) {
> +		iclk = omap2_cm_read_mod_reg(module, iclk_off);
> +		fclk = omap2_cm_read_mod_reg(module, fclk_off);
> +		while (wkst) {
> +			clken = wkst;
> +			omap2_cm_set_mod_reg_bits(clken, module, iclk_off);
> +			/*
> +			 * For USBHOST, we don't know whether HOST1 or
> +			 * HOST2 woke us up, so enable both f-clocks
> +			 */
> +			if (module == OMAP3430ES2_USBHOST_MOD)
> +				clken |= 1<<  OMAP3430ES2_EN_USBHOST2_SHIFT;
> +			omap2_cm_set_mod_reg_bits(clken, module, fclk_off);
> +			omap2_prm_write_mod_reg(wkst, module, wkst_off);
> +			wkst = omap2_prm_read_mod_reg(module, wkst_off);
> +			c++;
> +		}
> +		omap2_cm_write_mod_reg(iclk, module, iclk_off);
> +		omap2_cm_write_mod_reg(fclk, module, fclk_off);
> +	}
> +
> +	return c;
> +}
> +
> +/**
> + * omap3xxx_prm_clear_wakeups - clears wakeup event sources
> + * @events: active PRCM interrupt event mask
> + *
> + * This function will first check if PRCM chain handler detected
> + * a wakeup event or not. If yes, it will continue to clear any
> + * pending wakeup events from PRCM module. Typically the module
> + * will generate an actual interrupt together with the wakeup event,
> + * which will then be handled separately by the driver code.
> + */
> +void omap3xxx_prm_clear_wakeups(unsigned long *events)
> +{
> +	int c;
> +
> +	/*
> +	 * If we didn't come here because of a wakeup event, do nothing
> +	 */
> +	if (!(events[0]&  OMAP3430_WKUP_ST_MASK))
> +		return;
> +
> +	c = _prcm_clear_mod_irqs(WKUP_MOD, 1);
> +	c += _prcm_clear_mod_irqs(CORE_MOD, 1);
> +	c += _prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1);
> +	if (omap_rev()>  OMAP3430_REV_ES1_0) {
> +		c += _prcm_clear_mod_irqs(CORE_MOD, 3);
> +		c += _prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
> +	}
> +}
> +
> +/**
> + * _prcm_int_handle_wakeup - dummy irq handler for prcm wakeup event
> + * @irq: not used, irq common API
> + * @unused: not used, irq common API
> + *
> + * Dummy handler for PRCM wakeup event interrupt. On software level,
> + * this handler doesn't do anything, but it is needed for hardware
> + * to function properly. Adding this handler will enable the wakeup
> + * event generation from PRCM, which is needed to get CPU out of
> + * WFI. Otherwise the CPU will get stuck on the WFI instruction
> + * indefinitely, as the MPU powerdomain remains idle.
> + */
> +static irqreturn_t _prcm_int_handle_wakeup(int irq, void *unused)
> +{
> +	return IRQ_HANDLED;
> +}
> +
>   static int __init omap3xxx_prcm_init(void)
>   {
> -	int ret = 0;
> +	int ret;
>
>   	if (cpu_is_omap34xx()) {
>   		omap3xxx_prm_enable_io_wakeup();
>   		ret = omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
> -		if (!ret)
> -			irq_set_status_flags(omap_prcm_event_to_irq("io"),
> -					     IRQ_NOAUTOEN);
> +		if (ret) {
> +			pr_err("%s: failed to register chain handler: %d\n",
> +				__func__, ret);
> +			return ret;
> +		}
> +
> +		ret = request_irq(omap_prcm_event_to_irq("wkup"),
> +			_prcm_int_handle_wakeup, IRQF_NO_SUSPEND, "prcm_wkup",
> +			NULL);
> +		if (ret) {
> +			pr_err("%s: failed to request prcm_wkup irq: %d\n",
> +				__func__, ret);
> +			goto err;
> +		}
>   	}
>
> +	return 0;
> +err:
> +	omap_prcm_irq_cleanup();
>   	return ret;
>   }
>   subsys_initcall(omap3xxx_prcm_init);
> diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h
> index 1ba3d65..078df35 100644
> --- a/arch/arm/mach-omap2/prm2xxx_3xxx.h
> +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h
> @@ -322,6 +322,7 @@ extern void omap3xxx_prm_read_pending_irqs(unsigned long *events);
>   extern void omap3xxx_prm_ocp_barrier(void);
>   extern void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask);
>   extern void omap3xxx_prm_restore_irqen(u32 *saved_mask);
> +extern void omap3xxx_prm_clear_wakeups(unsigned long *events);
>
>   #endif	/* CONFIG_ARCH_OMAP4 */
>
> diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c
> index bb727c2..fd26279 100644
> --- a/arch/arm/mach-omap2/prm44xx.c
> +++ b/arch/arm/mach-omap2/prm44xx.c
> @@ -30,8 +30,8 @@
>   #include "prminst44xx.h"
>
>   static const struct omap_prcm_irq omap4_prcm_irqs[] = {
> -	OMAP_PRCM_IRQ("wkup",   0,      0),
> -	OMAP_PRCM_IRQ("io",     9,      1),
> +	OMAP_PRCM_IRQ("wkup",	0),
> +	OMAP_PRCM_IRQ("io",	9),
>   };
>
>   static struct omap_prcm_irq_setup omap4_prcm_irq_setup = {
> diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c
> index dfe00dd..4643651 100644
> --- a/arch/arm/mach-omap2/prm_common.c
> +++ b/arch/arm/mach-omap2/prm_common.c
> @@ -57,21 +57,6 @@ static struct omap_prcm_irq_setup *prcm_irq_setup;
>   /* Private functions */
>
>   /*
> - * Move priority events from events to priority_events array
> - */
> -static void omap_prcm_events_filter_priority(unsigned long *events,
> -	unsigned long *priority_events)
> -{
> -	int i;
> -
> -	for (i = 0; i<  prcm_irq_setup->nr_regs; i++) {
> -		priority_events[i] =
> -			events[i]&  prcm_irq_setup->priority_mask[i];
> -		events[i] ^= priority_events[i];
> -	}
> -}
> -
> -/*
>    * PRCM Interrupt Handler
>    *
>    * This is a common handler for the OMAP PRCM interrupts. Pending
> @@ -82,7 +67,6 @@ static void omap_prcm_events_filter_priority(unsigned long *events,
>   static void omap_prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
>   {
>   	unsigned long pending[OMAP_PRCM_MAX_NR_PENDING_REG];
> -	unsigned long priority_pending[OMAP_PRCM_MAX_NR_PENDING_REG];
>   	struct irq_chip *chip = irq_desc_get_chip(desc);
>   	unsigned int virtirq;
>   	int nr_irqs = prcm_irq_setup->nr_regs * 32;
> @@ -113,20 +97,19 @@ static void omap_prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
>   		if (find_first_bit(pending, nr_irqs)>= nr_irqs)
>   			break;
>
> -		omap_prcm_events_filter_priority(pending, priority_pending);
> -
>   		/*
>   		 * Loop on all currently pending irqs so that new irqs
>   		 * cannot starve previously pending irqs
>   		 */
> -
> -		/* Serve priority events first */
> -		for_each_set_bit(virtirq, priority_pending, nr_irqs)
> -			generic_handle_irq(prcm_irq_setup->base_irq + virtirq);
> -
> -		/* Serve normal events next */
>   		for_each_set_bit(virtirq, pending, nr_irqs)
>   			generic_handle_irq(prcm_irq_setup->base_irq + virtirq);
> +
> +		/*
> +		 * Ack pending events if needed, this will clean the
> +		 * wakeup events on omap3
> +		 */
> +		if (prcm_irq_setup->ack_pending_events)
> +			prcm_irq_setup->ack_pending_events(pending);
>   	}
>   	if (chip->irq_ack)
>   		chip->irq_ack(&desc->irq_data);
> @@ -191,9 +174,6 @@ void omap_prcm_irq_cleanup(void)
>   	kfree(prcm_irq_setup->saved_mask);
>   	prcm_irq_setup->saved_mask = NULL;
>
> -	kfree(prcm_irq_setup->priority_mask);
> -	prcm_irq_setup->priority_mask = NULL;
> -
>   	irq_set_chained_handler(prcm_irq_setup->irq, NULL);
>
>   	if (prcm_irq_setup->base_irq>  0)
> @@ -262,11 +242,8 @@ int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
>
>   	prcm_irq_chips = kzalloc(sizeof(void *) * nr_regs, GFP_KERNEL);
>   	prcm_irq_setup->saved_mask = kzalloc(sizeof(u32) * nr_regs, GFP_KERNEL);
> -	prcm_irq_setup->priority_mask = kzalloc(sizeof(u32) * nr_regs,
> -		GFP_KERNEL);
>
> -	if (!prcm_irq_chips || !prcm_irq_setup->saved_mask ||
> -	    !prcm_irq_setup->priority_mask) {
> +	if (!prcm_irq_chips || !prcm_irq_setup->saved_mask) {
>   		pr_err("PRCM: kzalloc failed\n");
>   		goto err;
>   	}
> @@ -276,9 +253,6 @@ int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
>   	for (i = 0; i<  irq_setup->nr_irqs; i++) {
>   		offset = irq_setup->irqs[i].offset;
>   		mask[offset>>  5] |= 1<<  (offset&  0x1f);
> -		if (irq_setup->irqs[i].priority)
> -			irq_setup->priority_mask[offset>>  5] |=
> -				1<<  (offset&  0x1f);
>   	}
>
>   	irq_set_chained_handler(irq_setup->irq, omap_prcm_irq_handler);

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

* Re: [RFC 1/6] ARM: OMAP3: PRM: move prcm interrupt handlers to PRM driver code
  2012-07-16 11:26     ` Rajendra Nayak
@ 2012-07-16 11:41       ` Tero Kristo
  -1 siblings, 0 replies; 30+ messages in thread
From: Tero Kristo @ 2012-07-16 11:41 UTC (permalink / raw)
  To: Rajendra Nayak; +Cc: linux-omap, paul, khilman, linux-arm-kernel

On Mon, 2012-07-16 at 16:56 +0530, Rajendra Nayak wrote:
> On Friday 13 July 2012 10:07 PM, Tero Kristo wrote:
> > PM code doesn't really care about the PRCM wakeup + io interrupts on
> > OMAP3, as these are used only for acking PRCM internal events, and the
> > IO chain handler is taken care of by hwmod code. Thus move the interrupt
> > handling logic from pm34xx.c to prm2xxx_3xxx.c file. This patch also
> > includes a minor cleanup for removing the priority handling and replacing
> > it with a mechanism for acking pending events. This gets rid of the need
> > for registering the shared interrupt handlers in specific order.
> 
> It would be easier to review if you were to split this into 2 patches,
> one which moves functions around as-is and another which does the
> cleanup/optimization. Having both in one is kinda hard to review.

The code was like that originally, however it was broken without the
cleanup / optimization. Simply moving the code around caused a problem
with idle: the sequencing of the interrupt handlers for IO event were
reversed and thus IO chain events for UARTs were never detected (they
were acked before parsing the chain.) Having these two things in
separate patches would introduce a bisect breakage for idle.

-Tero



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

* [RFC 1/6] ARM: OMAP3: PRM: move prcm interrupt handlers to PRM driver code
@ 2012-07-16 11:41       ` Tero Kristo
  0 siblings, 0 replies; 30+ messages in thread
From: Tero Kristo @ 2012-07-16 11:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 2012-07-16 at 16:56 +0530, Rajendra Nayak wrote:
> On Friday 13 July 2012 10:07 PM, Tero Kristo wrote:
> > PM code doesn't really care about the PRCM wakeup + io interrupts on
> > OMAP3, as these are used only for acking PRCM internal events, and the
> > IO chain handler is taken care of by hwmod code. Thus move the interrupt
> > handling logic from pm34xx.c to prm2xxx_3xxx.c file. This patch also
> > includes a minor cleanup for removing the priority handling and replacing
> > it with a mechanism for acking pending events. This gets rid of the need
> > for registering the shared interrupt handlers in specific order.
> 
> It would be easier to review if you were to split this into 2 patches,
> one which moves functions around as-is and another which does the
> cleanup/optimization. Having both in one is kinda hard to review.

The code was like that originally, however it was broken without the
cleanup / optimization. Simply moving the code around caused a problem
with idle: the sequencing of the interrupt handlers for IO event were
reversed and thus IO chain events for UARTs were never detected (they
were acked before parsing the chain.) Having these two things in
separate patches would introduce a bisect breakage for idle.

-Tero

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

* Re: [RFC 0/6] ARM: OMAP3+: minor PM core code cleanup
  2012-07-13 16:37 ` Tero Kristo
@ 2012-07-30 20:53   ` Kevin Hilman
  -1 siblings, 0 replies; 30+ messages in thread
From: Kevin Hilman @ 2012-07-30 20:53 UTC (permalink / raw)
  To: Tero Kristo; +Cc: linux-omap, paul, linux-arm-kernel

Tero, Paul,

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

> Hi,
>
> Following set moves some PRM related code away from PM core code to
> PRM / HWMOD. This requires the hwmod cleanup set from Paul that
> implements the setup_preprogram hooks for hwmods. Sending as RFC for
> initial commenting.

What is the status of the setup_preprogram hooks patch(es)?  Looks like
that part was dropped from Paul's original series of fixes.

Just curious,

Kevin

> This set does following:
> - gets rid of the prcm interrupt handler from pm34xx.c
> - removes iva_idle from pm34xx.c
> - removes d2d_idle from pm34xx.c
>
> There are some side-effects though, it looks like the reset statuses
> for iva / d2d modules are rather flaky, and some failed hardreset
> warnings are generated during boot. PM works fine though and the
> modules are put to idle properly. Could use some ideas how to handle
> this, maybe add a flag for ignoring the hardreset status completely...?
>
> -Tero
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [RFC 0/6] ARM: OMAP3+: minor PM core code cleanup
@ 2012-07-30 20:53   ` Kevin Hilman
  0 siblings, 0 replies; 30+ messages in thread
From: Kevin Hilman @ 2012-07-30 20:53 UTC (permalink / raw)
  To: linux-arm-kernel

Tero, Paul,

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

> Hi,
>
> Following set moves some PRM related code away from PM core code to
> PRM / HWMOD. This requires the hwmod cleanup set from Paul that
> implements the setup_preprogram hooks for hwmods. Sending as RFC for
> initial commenting.

What is the status of the setup_preprogram hooks patch(es)?  Looks like
that part was dropped from Paul's original series of fixes.

Just curious,

Kevin

> This set does following:
> - gets rid of the prcm interrupt handler from pm34xx.c
> - removes iva_idle from pm34xx.c
> - removes d2d_idle from pm34xx.c
>
> There are some side-effects though, it looks like the reset statuses
> for iva / d2d modules are rather flaky, and some failed hardreset
> warnings are generated during boot. PM works fine though and the
> modules are put to idle properly. Could use some ideas how to handle
> this, maybe add a flag for ignoring the hardreset status completely...?
>
> -Tero
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [RFC 1/6] ARM: OMAP3: PRM: move prcm interrupt handlers to PRM driver code
  2012-07-13 16:37   ` Tero Kristo
@ 2012-07-31  0:31     ` Kevin Hilman
  -1 siblings, 0 replies; 30+ messages in thread
From: Kevin Hilman @ 2012-07-31  0:31 UTC (permalink / raw)
  To: Tero Kristo; +Cc: linux-omap, paul, linux-arm-kernel

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

> PM code doesn't really care about the PRCM wakeup + io interrupts on
> OMAP3, as these are used only for acking PRCM internal events, and the
> IO chain handler is taken care of by hwmod code. Thus move the interrupt
> handling logic from pm34xx.c to prm2xxx_3xxx.c file. This patch also
> includes a minor cleanup for removing the priority handling and replacing
> it with a mechanism for acking pending events. This gets rid of the need
> for registering the shared interrupt handlers in specific order.
>
> Signed-off-by: Tero Kristo <t-kristo@ti.com>

Like Rajendra, I found this combination a bit difficult to review, so I
decided to apply it and test it first.

Testing with just this patch (on top of Paul's omap4_warnings_fix_3.6
branch, which has the setup_preprogram hooks), and I get a hang on
3530 and 3730 Overo platforms (works fine on 3430/n900 and 3630/xM.)

I'm not sure what is happening yet, but there seems to be a race between
the IO and wkup handlers...

[...]

> +/**
> + * omap3xxx_prm_clear_wakeups - clears wakeup event sources
> + * @events: active PRCM interrupt event mask
> + *
> + * This function will first check if PRCM chain handler detected
> + * a wakeup event or not. If yes, it will continue to clear any
> + * pending wakeup events from PRCM module. Typically the module
> + * will generate an actual interrupt together with the wakeup event,
> + * which will then be handled separately by the driver code.
> + */
> +void omap3xxx_prm_clear_wakeups(unsigned long *events)
> +{
> +	int c;
> +
> +	/*
> +	 * If we didn't come here because of a wakeup event, do nothing
> +	 */
> +	if (!(events[0] & OMAP3430_WKUP_ST_MASK))
> +		return;

... because if I comment out the above two lines, it goes back to
working again.

> +	c = _prcm_clear_mod_irqs(WKUP_MOD, 1);
> +	c += _prcm_clear_mod_irqs(CORE_MOD, 1);
> +	c += _prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1);
> +	if (omap_rev() > OMAP3430_REV_ES1_0) {
> +		c += _prcm_clear_mod_irqs(CORE_MOD, 3);
> +		c += _prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
> +	}
> +}

At first, I wasn't sure why this was happening on Overo boards and not
on the other boards, but then I notcied there was a *lot* more pm_wkup
interrupts during boot on Overo compared to the other boards.  This is
because of the GPIO IRQ for the network interface as well as the network
stack itself setting timers, resulting in a lot more pm_wkup events
during boot and making the race more likely.

Kevin


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

* [RFC 1/6] ARM: OMAP3: PRM: move prcm interrupt handlers to PRM driver code
@ 2012-07-31  0:31     ` Kevin Hilman
  0 siblings, 0 replies; 30+ messages in thread
From: Kevin Hilman @ 2012-07-31  0:31 UTC (permalink / raw)
  To: linux-arm-kernel

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

> PM code doesn't really care about the PRCM wakeup + io interrupts on
> OMAP3, as these are used only for acking PRCM internal events, and the
> IO chain handler is taken care of by hwmod code. Thus move the interrupt
> handling logic from pm34xx.c to prm2xxx_3xxx.c file. This patch also
> includes a minor cleanup for removing the priority handling and replacing
> it with a mechanism for acking pending events. This gets rid of the need
> for registering the shared interrupt handlers in specific order.
>
> Signed-off-by: Tero Kristo <t-kristo@ti.com>

Like Rajendra, I found this combination a bit difficult to review, so I
decided to apply it and test it first.

Testing with just this patch (on top of Paul's omap4_warnings_fix_3.6
branch, which has the setup_preprogram hooks), and I get a hang on
3530 and 3730 Overo platforms (works fine on 3430/n900 and 3630/xM.)

I'm not sure what is happening yet, but there seems to be a race between
the IO and wkup handlers...

[...]

> +/**
> + * omap3xxx_prm_clear_wakeups - clears wakeup event sources
> + * @events: active PRCM interrupt event mask
> + *
> + * This function will first check if PRCM chain handler detected
> + * a wakeup event or not. If yes, it will continue to clear any
> + * pending wakeup events from PRCM module. Typically the module
> + * will generate an actual interrupt together with the wakeup event,
> + * which will then be handled separately by the driver code.
> + */
> +void omap3xxx_prm_clear_wakeups(unsigned long *events)
> +{
> +	int c;
> +
> +	/*
> +	 * If we didn't come here because of a wakeup event, do nothing
> +	 */
> +	if (!(events[0] & OMAP3430_WKUP_ST_MASK))
> +		return;

... because if I comment out the above two lines, it goes back to
working again.

> +	c = _prcm_clear_mod_irqs(WKUP_MOD, 1);
> +	c += _prcm_clear_mod_irqs(CORE_MOD, 1);
> +	c += _prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1);
> +	if (omap_rev() > OMAP3430_REV_ES1_0) {
> +		c += _prcm_clear_mod_irqs(CORE_MOD, 3);
> +		c += _prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
> +	}
> +}

At first, I wasn't sure why this was happening on Overo boards and not
on the other boards, but then I notcied there was a *lot* more pm_wkup
interrupts during boot on Overo compared to the other boards.  This is
because of the GPIO IRQ for the network interface as well as the network
stack itself setting timers, resulting in a lot more pm_wkup events
during boot and making the race more likely.

Kevin

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

* Re: [RFC 1/6] ARM: OMAP3: PRM: move prcm interrupt handlers to PRM driver code
  2012-07-31  0:31     ` Kevin Hilman
@ 2012-08-07  7:28       ` Tony Lindgren
  -1 siblings, 0 replies; 30+ messages in thread
From: Tony Lindgren @ 2012-08-07  7:28 UTC (permalink / raw)
  To: Kevin Hilman; +Cc: Tero Kristo, linux-omap, paul, linux-arm-kernel

* Kevin Hilman <khilman@ti.com> [120730 17:36]:
> 
> At first, I wasn't sure why this was happening on Overo boards and not
> on the other boards, but then I notcied there was a *lot* more pm_wkup
> interrupts during boot on Overo compared to the other boards.  This is
> because of the GPIO IRQ for the network interface as well as the network
> stack itself setting timers, resulting in a lot more pm_wkup events
> during boot and making the race more likely.

Also happens if you may have somehow both edges selected for GPIO
interrupts. Might be worth checking at least just in case of bugs
somewhere..

Tony

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

* [RFC 1/6] ARM: OMAP3: PRM: move prcm interrupt handlers to PRM driver code
@ 2012-08-07  7:28       ` Tony Lindgren
  0 siblings, 0 replies; 30+ messages in thread
From: Tony Lindgren @ 2012-08-07  7:28 UTC (permalink / raw)
  To: linux-arm-kernel

* Kevin Hilman <khilman@ti.com> [120730 17:36]:
> 
> At first, I wasn't sure why this was happening on Overo boards and not
> on the other boards, but then I notcied there was a *lot* more pm_wkup
> interrupts during boot on Overo compared to the other boards.  This is
> because of the GPIO IRQ for the network interface as well as the network
> stack itself setting timers, resulting in a lot more pm_wkup events
> during boot and making the race more likely.

Also happens if you may have somehow both edges selected for GPIO
interrupts. Might be worth checking at least just in case of bugs
somewhere..

Tony

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

end of thread, other threads:[~2012-08-07  7:28 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-13 16:37 [RFC 0/6] ARM: OMAP3+: minor PM core code cleanup Tero Kristo
2012-07-13 16:37 ` Tero Kristo
2012-07-13 16:37 ` [RFC 1/6] ARM: OMAP3: PRM: move prcm interrupt handlers to PRM driver code Tero Kristo
2012-07-13 16:37   ` Tero Kristo
2012-07-16 11:26   ` Rajendra Nayak
2012-07-16 11:26     ` Rajendra Nayak
2012-07-16 11:41     ` Tero Kristo
2012-07-16 11:41       ` Tero Kristo
2012-07-31  0:31   ` Kevin Hilman
2012-07-31  0:31     ` Kevin Hilman
2012-08-07  7:28     ` Tony Lindgren
2012-08-07  7:28       ` Tony Lindgren
2012-07-13 16:37 ` [RFC 2/6] ARM: OMAP3: clock data: prevent IVA2 DPLL low power stop mode Tero Kristo
2012-07-13 16:37   ` Tero Kristo
2012-07-13 16:37 ` [RFC 3/6] ARM: OMAP3: hwmod data: fix iva2 reset info Tero Kristo
2012-07-13 16:37   ` Tero Kristo
2012-07-16  0:12   ` Paul Walmsley
2012-07-16  0:12     ` Paul Walmsley
2012-07-13 16:37 ` [RFC 4/6] ARM: OMAP3: hwmod data: add custom setup_preprogram for iva hwmod Tero Kristo
2012-07-13 16:37   ` Tero Kristo
2012-07-13 16:37 ` [RFC 5/6] ARM: OMAP3: hwmod data: add sad2d hwmod Tero Kristo
2012-07-13 16:37   ` Tero Kristo
2012-07-16  1:14   ` Paul Walmsley
2012-07-16  1:14     ` Paul Walmsley
2012-07-16  1:28   ` Paul Walmsley
2012-07-16  1:28     ` Paul Walmsley
2012-07-13 16:37 ` [RFC 6/6] ARM: OMAP3: hwmod data: add custom setup_preprogram for " Tero Kristo
2012-07-13 16:37   ` Tero Kristo
2012-07-30 20:53 ` [RFC 0/6] ARM: OMAP3+: minor PM core code cleanup Kevin Hilman
2012-07-30 20:53   ` Kevin Hilman

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.