All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/11] OMAP2/3: PM sync-up
@ 2009-05-15 18:40 Kevin Hilman
  2009-05-15 18:40 ` [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap Kevin Hilman
  0 siblings, 1 reply; 31+ messages in thread
From: Kevin Hilman @ 2009-05-15 18:40 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: linux-omap, Kevin Hilman

This series is intended to push the core PM support from linux-omap
into mainline.  It applies on top of Tony's two recent series:

- [PATCH 0/8] Omap fixes for 2.6.30-rc5
- [PATCH 0/5] More omap header clean-up for the merge window after 2.6.30

Upon review/acceptance, Tony will merge into is for-next branch so
all OMAP stuff can come from one place.

In addition to the linux-omap sync, several OMAP3 init fixes are
required to ensure that the chip can hit full-chip retention
on idle and suspend.

Compile tested on OMAP2, Boot tested on OMAP3430SDP and can
hit full-chip retention in suspend and in idle.

Jouni Hogander (1):
  OMAP: Add new function to check wether there is irq pending

Kevin Hilman (9):
  OMAP2/3: PM: push core PM code from linux-omap
  OMAP3: PM: Force IVA2 into idle during bootup
  OMAP3: PM: Add wake-up bit defintiions for CONTROL_PADCONF_X
  OMAP3: PM: UART: disable clocks when idle and off-mode support
  OMAP3: PM: Add D2D clocks and auto-idle setup to PRCM init
  OMAP3: PM: D2D clockdomain supports SW supervised transitions
  OMAP3: PM: Ensure PRCM interrupts are cleared at boot
  OMAP3: PM: Clear pending PRCM reset flags on init
  OMAP3: PM: prevent module wakeups from waking IVA2

Peter 'p2' De Schrijver (1):
  OMAP3: PM: Ensure MUSB block can idle when driver not loaded

 arch/arm/mach-omap2/Makefile              |    3 +
 arch/arm/mach-omap2/clock34xx.c           |    3 +
 arch/arm/mach-omap2/clock34xx.h           |   33 ++-
 arch/arm/mach-omap2/clockdomains.h        |    2 +-
 arch/arm/mach-omap2/cm-regbits-34xx.h     |   14 +
 arch/arm/mach-omap2/irq.c                 |   17 +-
 arch/arm/mach-omap2/pm-debug.c            |  152 ++++++
 arch/arm/mach-omap2/pm.c                  |  155 ++++---
 arch/arm/mach-omap2/pm.h                  |   53 +++
 arch/arm/mach-omap2/pm24xx.c              |  558 ++++++++++++++++++++++
 arch/arm/mach-omap2/pm34xx.c              |  711 +++++++++++++++++++++++++++++
 arch/arm/mach-omap2/prcm-common.h         |    2 +
 arch/arm/mach-omap2/prm.h                 |    2 +
 arch/arm/mach-omap2/sdrc.c                |    5 +-
 arch/arm/mach-omap2/serial.c              |  391 +++++++++++++++-
 arch/arm/mach-omap2/sleep24xx.S           |    1 -
 arch/arm/mach-omap2/sleep34xx.S           |  543 ++++++++++++++++++++++
 arch/arm/mach-omap2/usb-musb.c            |    7 +-
 arch/arm/plat-omap/Kconfig                |    2 +-
 arch/arm/plat-omap/common.c               |    1 -
 arch/arm/plat-omap/include/mach/common.h  |    2 -
 arch/arm/plat-omap/include/mach/control.h |   13 +
 arch/arm/plat-omap/include/mach/irqs.h    |    1 +
 arch/arm/plat-omap/include/mach/pm.h      |  345 --------------
 arch/arm/plat-omap/include/mach/serial.h  |    9 +
 drivers/mtd/onenand/omap2.c               |    1 -
 26 files changed, 2570 insertions(+), 456 deletions(-)
 create mode 100644 arch/arm/mach-omap2/pm-debug.c
 create mode 100644 arch/arm/mach-omap2/pm.h
 create mode 100644 arch/arm/mach-omap2/pm24xx.c
 create mode 100644 arch/arm/mach-omap2/pm34xx.c
 create mode 100644 arch/arm/mach-omap2/sleep34xx.S
 delete mode 100644 arch/arm/plat-omap/include/mach/pm.h


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

* [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap
  2009-05-15 18:40 [PATCH 00/11] OMAP2/3: PM sync-up Kevin Hilman
@ 2009-05-15 18:40 ` Kevin Hilman
  2009-05-15 18:40   ` [PATCH 02/11] OMAP: Add new function to check wether there is irq pending Kevin Hilman
  2009-05-18 13:32   ` [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap Russell King - ARM Linux
  0 siblings, 2 replies; 31+ messages in thread
From: Kevin Hilman @ 2009-05-15 18:40 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: linux-omap, Kevin Hilman, Jouni Hogander, Paul Walmsley

This patch is to sync the core linux-omap PM code with mainline.  This
code has evolved and been used for a while the linux-omap tree, but
the attempt here is to finally get this into mainline.

Following this will be a series of patches from the 'PM branch' of the
linux-omap tree to add full PM hardware support from the linux-omap
tree.

Much of this PM core code was written by Jouni Hogander with
significant contributions from Paul Walmsley as well as many others
from Nokia, Texas Instruments and linux-omap community.

Signed-off-by: Jouni Hogander <jouni.hogander@nokia.com>
Cc: Paul Walmsley <paul@pwsan.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
 arch/arm/mach-omap2/Makefile         |    3 +
 arch/arm/mach-omap2/pm-debug.c       |  152 +++++++++
 arch/arm/mach-omap2/pm.c             |  155 +++++-----
 arch/arm/mach-omap2/pm.h             |   53 +++
 arch/arm/mach-omap2/pm24xx.c         |  557 +++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/pm34xx.c         |  607 ++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/prcm-common.h    |    2 +
 arch/arm/mach-omap2/sdrc.c           |    5 +-
 arch/arm/mach-omap2/sleep24xx.S      |    1 -
 arch/arm/mach-omap2/sleep34xx.S      |  543 ++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/usb-musb.c       |    1 -
 arch/arm/plat-omap/Kconfig           |    2 +-
 arch/arm/plat-omap/common.c          |    1 -
 arch/arm/plat-omap/include/mach/pm.h |  345 -------------------
 drivers/mtd/onenand/omap2.c          |    1 -
 15 files changed, 2002 insertions(+), 426 deletions(-)
 create mode 100644 arch/arm/mach-omap2/pm-debug.c
 create mode 100644 arch/arm/mach-omap2/pm.h
 create mode 100644 arch/arm/mach-omap2/pm24xx.c
 create mode 100644 arch/arm/mach-omap2/pm34xx.c
 create mode 100644 arch/arm/mach-omap2/sleep34xx.S
 delete mode 100644 arch/arm/plat-omap/include/mach/pm.h

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index e4f6f61..f6383a0 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -26,7 +26,10 @@ obj-$(CONFIG_ARCH_OMAP2)		+= sdrc2xxx.o
 # Power Management
 ifeq ($(CONFIG_PM),y)
 obj-y					+= pm.o
+obj-$(CONFIG_ARCH_OMAP2)		+= pm24xx.o
 obj-$(CONFIG_ARCH_OMAP24XX)		+= sleep24xx.o
+obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o
+obj-$(CONFIG_PM_DEBUG)			+= pm-debug.o
 endif
 
 # Clock framework
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
new file mode 100644
index 0000000..6cc375a
--- /dev/null
+++ b/arch/arm/mach-omap2/pm-debug.c
@@ -0,0 +1,152 @@
+/*
+ * OMAP Power Management debug routines
+ *
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * Written by:
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Tony Lindgren
+ * Juha Yrjola
+ * Amit Kucheria <amit.kucheria@nokia.com>
+ * Igor Stoppa <igor.stoppa@nokia.com>
+ * Jouni Hogander
+ *
+ * Based on pm.c for omap2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <mach/clock.h>
+#include <mach/board.h>
+
+#include "prm.h"
+#include "cm.h"
+#include "pm.h"
+
+int omap2_pm_debug;
+
+#define DUMP_PRM_MOD_REG(mod, reg)    \
+	regs[reg_count].name = #mod "." #reg; \
+	regs[reg_count++].val = prm_read_mod_reg(mod, reg)
+#define DUMP_CM_MOD_REG(mod, reg)     \
+	regs[reg_count].name = #mod "." #reg; \
+	regs[reg_count++].val = cm_read_mod_reg(mod, reg)
+#define DUMP_PRM_REG(reg) \
+	regs[reg_count].name = #reg; \
+	regs[reg_count++].val = __raw_readl(reg)
+#define DUMP_CM_REG(reg) \
+	regs[reg_count].name = #reg; \
+	regs[reg_count++].val = __raw_readl(reg)
+#define DUMP_INTC_REG(reg, off) \
+	regs[reg_count].name = #reg; \
+	regs[reg_count++].val = __raw_readl(IO_ADDRESS(0x480fe000 + (off)))
+
+void omap2_pm_dump(int mode, int resume, unsigned int us)
+{
+	struct reg {
+		const char *name;
+		u32 val;
+	} regs[32];
+	int reg_count = 0, i;
+	const char *s1 = NULL, *s2 = NULL;
+
+	if (!resume) {
+#if 0
+		/* MPU */
+		DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRM_IRQENABLE_MPU_OFFSET);
+		DUMP_CM_MOD_REG(MPU_MOD, CM_CLKSTCTRL);
+		DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTCTRL);
+		DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTST);
+		DUMP_PRM_MOD_REG(MPU_MOD, PM_WKDEP);
+#endif
+#if 0
+		/* INTC */
+		DUMP_INTC_REG(INTC_MIR0, 0x0084);
+		DUMP_INTC_REG(INTC_MIR1, 0x00a4);
+		DUMP_INTC_REG(INTC_MIR2, 0x00c4);
+#endif
+#if 0
+		DUMP_CM_MOD_REG(CORE_MOD, CM_FCLKEN1);
+		if (cpu_is_omap24xx()) {
+			DUMP_CM_MOD_REG(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+			DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD,
+					OMAP2_PRCM_CLKEMUL_CTRL_OFFSET);
+			DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD,
+					OMAP2_PRCM_CLKSRC_CTRL_OFFSET);
+		}
+		DUMP_CM_MOD_REG(WKUP_MOD, CM_FCLKEN);
+		DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN1);
+		DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN2);
+		DUMP_CM_MOD_REG(WKUP_MOD, CM_ICLKEN);
+		DUMP_CM_MOD_REG(PLL_MOD, CM_CLKEN);
+		DUMP_CM_MOD_REG(PLL_MOD, CM_AUTOIDLE);
+		DUMP_PRM_MOD_REG(CORE_MOD, PM_PWSTST);
+#endif
+#if 0
+		/* DSP */
+		if (cpu_is_omap24xx()) {
+			DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_FCLKEN);
+			DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_ICLKEN);
+			DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_IDLEST);
+			DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_AUTOIDLE);
+			DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSEL);
+			DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSTCTRL);
+			DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTCTRL);
+			DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTST);
+			DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTCTRL);
+			DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTST);
+		}
+#endif
+	} else {
+		DUMP_PRM_MOD_REG(CORE_MOD, PM_WKST1);
+		if (cpu_is_omap24xx())
+			DUMP_PRM_MOD_REG(CORE_MOD, OMAP24XX_PM_WKST2);
+		DUMP_PRM_MOD_REG(WKUP_MOD, PM_WKST);
+		DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
+#if 1
+		DUMP_INTC_REG(INTC_PENDING_IRQ0, 0x0098);
+		DUMP_INTC_REG(INTC_PENDING_IRQ1, 0x00b8);
+		DUMP_INTC_REG(INTC_PENDING_IRQ2, 0x00d8);
+#endif
+	}
+
+	switch (mode) {
+	case 0:
+		s1 = "full";
+		s2 = "retention";
+		break;
+	case 1:
+		s1 = "MPU";
+		s2 = "retention";
+		break;
+	case 2:
+		s1 = "MPU";
+		s2 = "idle";
+		break;
+	}
+
+	if (!resume)
+#ifdef CONFIG_NO_HZ
+		printk(KERN_INFO
+		       "--- Going to %s %s (next timer after %u ms)\n", s1, s2,
+		       jiffies_to_msecs(get_next_timer_interrupt(jiffies) -
+					jiffies));
+#else
+		printk(KERN_INFO "--- Going to %s %s\n", s1, s2);
+#endif
+	else
+		printk(KERN_INFO "--- Woke up (slept for %u.%03u ms)\n",
+			us / 1000, us % 1000);
+
+	for (i = 0; i < reg_count; i++)
+		printk(KERN_INFO "%-20s: 0x%08x\n", regs[i].name, regs[i].val);
+}
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index ea8ceae..ab82c49 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -1,13 +1,16 @@
 /*
- * linux/arch/arm/mach-omap2/pm.c
- *
- * OMAP2 Power Management Routines
- *
- * Copyright (C) 2006 Nokia Corporation
- * Tony Lindgren <tony@atomide.com>
+ * OMAP2/3 Power Management Common Routines
  *
  * Copyright (C) 2005 Texas Instruments, Inc.
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * Written by:
  * Richard Woodruff <r-woodruff2@ti.com>
+ * Tony Lindgren
+ * Juha Yrjola
+ * Amit Kucheria <amit.kucheria@nokia.com>
+ * Igor Stoppa <igor.stoppa@nokia.com>
+ * Jouni Hogander
  *
  * Based on pm.c for omap1
  *
@@ -17,95 +20,97 @@
  */
 
 #include <linux/suspend.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/interrupt.h>
-#include <linux/sysfs.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/atomic.h>
-#include <asm/mach/time.h>
-#include <asm/mach/irq.h>
+#include <linux/time.h>
 
-#include <mach/irqs.h>
-#include <mach/clock.h>
-#include <mach/sram.h>
-#include <mach/pm.h>
+#include <mach/cpu.h>
+#include <asm/mach/time.h>
+#include <asm/atomic.h>
 
-static struct clk *vclk;
-static void (*omap2_sram_idle)(void);
-static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev);
-static void (*saved_idle)(void);
+#include "pm.h"
 
-extern void __init pmdomain_init(void);
-extern void pmdomain_set_autoidle(void);
+unsigned short enable_dyn_sleep;
+unsigned short clocks_off_while_idle;
+atomic_t sleep_block = ATOMIC_INIT(0);
 
-static unsigned int omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_SIZE];
+static ssize_t idle_show(struct kobject *, struct kobj_attribute *, char *);
+static ssize_t idle_store(struct kobject *k, struct kobj_attribute *,
+			  const char *buf, size_t n);
 
-void omap2_pm_idle(void)
-{
-	local_irq_disable();
-	local_fiq_disable();
-	if (need_resched()) {
-		local_fiq_enable();
-		local_irq_enable();
-		return;
-	}
+static struct kobj_attribute sleep_while_idle_attr =
+	__ATTR(sleep_while_idle, 0644, idle_show, idle_store);
 
-	omap2_sram_idle();
-	local_fiq_enable();
-	local_irq_enable();
-}
+static struct kobj_attribute clocks_off_while_idle_attr =
+	__ATTR(clocks_off_while_idle, 0644, idle_show, idle_store);
 
-static int omap2_pm_prepare(void)
+static ssize_t idle_show(struct kobject *kobj, struct kobj_attribute *attr,
+			 char *buf)
 {
-	/* We cannot sleep in idle until we have resumed */
-	saved_idle = pm_idle;
-	pm_idle = NULL;
-	return 0;
+	if (attr == &sleep_while_idle_attr)
+		return sprintf(buf, "%hu\n", enable_dyn_sleep);
+	else if (attr == &clocks_off_while_idle_attr)
+		return sprintf(buf, "%hu\n", clocks_off_while_idle);
+	else
+		return -EINVAL;
 }
 
-static int omap2_pm_suspend(void)
+static ssize_t idle_store(struct kobject *kobj, struct kobj_attribute *attr,
+			  const char *buf, size_t n)
 {
-	return 0;
-}
+	unsigned short value;
 
-static int omap2_pm_enter(suspend_state_t state)
-{
-	int ret = 0;
-
-	switch (state)
-	{
-	case PM_SUSPEND_STANDBY:
-	case PM_SUSPEND_MEM:
-		ret = omap2_pm_suspend();
-		break;
-	default:
-		ret = -EINVAL;
+	if (sscanf(buf, "%hu", &value) != 1 ||
+	    (value != 0 && value != 1)) {
+		printk(KERN_ERR "idle_store: Invalid value\n");
+		return -EINVAL;
 	}
 
-	return ret;
+	if (attr == &sleep_while_idle_attr)
+		enable_dyn_sleep = value;
+	else if (attr == &clocks_off_while_idle_attr)
+		clocks_off_while_idle = value;
+	else
+		return -EINVAL;
+
+	return n;
 }
 
-static void omap2_pm_finish(void)
+void omap2_block_sleep(void)
 {
-	pm_idle = saved_idle;
+	atomic_inc(&sleep_block);
 }
 
-static struct platform_suspend_ops omap_pm_ops = {
-	.prepare	= omap2_pm_prepare,
-	.enter		= omap2_pm_enter,
-	.finish		= omap2_pm_finish,
-	.valid		= suspend_valid_only_mem,
-};
+void omap2_allow_sleep(void)
+{
+	int i;
 
-static int __init omap2_pm_init(void)
+	i = atomic_dec_return(&sleep_block);
+	BUG_ON(i < 0);
+}
+
+static int __init omap_pm_init(void)
 {
-	return 0;
+	int error = -1;
+
+	if (cpu_is_omap24xx())
+		error = omap2_pm_init();
+	if (cpu_is_omap34xx())
+		error = omap3_pm_init();
+	if (error) {
+		printk(KERN_ERR "omap2|3_pm_init failed: %d\n", error);
+		return error;
+	}
+
+	/* disabled till drivers are fixed */
+	enable_dyn_sleep = 0;
+	error = sysfs_create_file(power_kobj, &sleep_while_idle_attr.attr);
+	if (error)
+		printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
+	error = sysfs_create_file(power_kobj,
+				  &clocks_off_while_idle_attr.attr);
+	if (error)
+		printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
+
+	return error;
 }
 
-__initcall(omap2_pm_init);
+late_initcall(omap_pm_init);
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
new file mode 100644
index 0000000..8492954
--- /dev/null
+++ b/arch/arm/mach-omap2/pm.h
@@ -0,0 +1,53 @@
+/*
+ * OMAP2/3 Power Management Routines
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Jouni Hogander
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __ARCH_ARM_MACH_OMAP2_PM_H
+#define __ARCH_ARM_MACH_OMAP2_PM_H
+
+extern int omap2_pm_init(void);
+extern int omap3_pm_init(void);
+
+extern unsigned short enable_dyn_sleep;
+extern unsigned short clocks_off_while_idle;
+extern atomic_t sleep_block;
+
+extern void omap2_block_sleep(void);
+extern void omap2_allow_sleep(void);
+
+#ifdef CONFIG_PM_DEBUG
+extern void omap2_pm_dump(int mode, int resume, unsigned int us);
+extern int omap2_pm_debug;
+#else
+#define omap2_pm_dump(mode, resume, us)		do {} while (0);
+#define omap2_pm_debug				0
+#endif /* CONFIG_PM_DEBUG */
+
+extern void omap24xx_idle_loop_suspend(void);
+
+extern void omap24xx_cpu_suspend(u32 dll_ctrl, void __iomem *sdrc_dlla_ctrl,
+					void __iomem *sdrc_power);
+extern void omap34xx_cpu_suspend(u32 *addr, int save_state);
+extern void save_secure_ram_context(u32 *addr);
+
+#ifdef CONFIG_PM
+extern void omap2_block_sleep(void);
+extern void omap2_allow_sleep(void);
+#else
+static inline void omap2_block_sleep(void) { }
+static inline void omap2_allow_sleep(void) { }
+#endif
+
+extern unsigned int omap24xx_idle_loop_suspend_sz;
+extern unsigned int omap34xx_suspend_sz;
+extern unsigned int save_secure_ram_context_sz;
+extern unsigned int omap24xx_cpu_suspend_sz;
+extern unsigned int omap34xx_cpu_suspend_sz;
+
+#endif
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
new file mode 100644
index 0000000..2a2d1a3
--- /dev/null
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -0,0 +1,557 @@
+/*
+ * OMAP2 Power Management Routines
+ *
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * Written by:
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Tony Lindgren
+ * Juha Yrjola
+ * Amit Kucheria <amit.kucheria@nokia.com>
+ * Igor Stoppa <igor.stoppa@nokia.com>
+ *
+ * Based on pm.c for omap1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/suspend.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/interrupt.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/time.h>
+
+#include <asm/mach/time.h>
+#include <asm/mach/irq.h>
+#include <asm/mach-types.h>
+
+#include <mach/irqs.h>
+#include <mach/clock.h>
+#include <mach/sram.h>
+#include <mach/control.h>
+#include <mach/gpio.h>
+#include <mach/mux.h>
+#include <mach/dma.h>
+#include <mach/board.h>
+
+#include "prm.h"
+#include "prm-regbits-24xx.h"
+#include "cm.h"
+#include "cm-regbits-24xx.h"
+#include "sdrc.h"
+#include "pm.h"
+
+#include <mach/powerdomain.h>
+#include <mach/clockdomain.h>
+
+static void (*omap2_sram_idle)(void);
+static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl,
+				  void __iomem *sdrc_power);
+static void (*saved_idle)(void);
+
+static struct powerdomain *mpu_pwrdm;
+static struct powerdomain *core_pwrdm;
+
+static struct clockdomain *dsp_clkdm;
+static struct clockdomain *gfx_clkdm;
+
+static struct clk *osc_ck, *emul_ck;
+
+static int omap2_fclks_active(void)
+{
+	u32 f1, f2;
+
+	f1 = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+	f2 = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+	if (f1 | f2)
+		return 1;
+	return 0;
+}
+
+static int omap2_irq_pending(void)
+{
+	u32 pending_reg = 0x480fe098;
+	int i;
+
+	for (i = 0; i < 4; i++) {
+		if (omap_readl(pending_reg))
+			return 1;
+		pending_reg += 0x20;
+	}
+	return 0;
+}
+
+static void omap2_enter_full_retention(void)
+{
+	u32 l;
+	struct timespec ts_preidle, ts_postidle, ts_idle;
+
+	/* There is 1 reference hold for all children of the oscillator
+	 * clock, the following will remove it. If no one else uses the
+	 * oscillator itself it will be disabled if/when we enter retention
+	 * mode.
+	 */
+	clk_disable(osc_ck);
+
+	/* Clear old wake-up events */
+	/* REVISIT: These write to reserved bits? */
+	prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
+	prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
+	prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
+
+	/*
+	 * Set MPU powerdomain's next power state to RETENTION;
+	 * preserve logic state during retention
+	 */
+	pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
+	pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
+
+	/* Workaround to kill USB */
+	l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL;
+	omap_ctrl_writel(l, OMAP2_CONTROL_DEVCONF0);
+
+	omap2_gpio_prepare_for_retention();
+
+	if (omap2_pm_debug) {
+		omap2_pm_dump(0, 0, 0);
+		getnstimeofday(&ts_preidle);
+	}
+
+	/* One last check for pending IRQs to avoid extra latency due
+	 * to sleeping unnecessarily. */
+	if (omap2_irq_pending())
+		goto no_sleep;
+
+	/* Jump to SRAM suspend code */
+	omap2_sram_suspend(sdrc_read_reg(SDRC_DLLA_CTRL),
+			   OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL),
+			   OMAP_SDRC_REGADDR(SDRC_POWER));
+no_sleep:
+
+	if (omap2_pm_debug) {
+		unsigned long long tmp;
+
+		getnstimeofday(&ts_postidle);
+		ts_idle = timespec_sub(ts_postidle, ts_preidle);
+		tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC;
+		omap2_pm_dump(0, 1, tmp);
+	}
+	omap2_gpio_resume_after_retention();
+
+	clk_enable(osc_ck);
+
+	/* clear CORE wake-up events */
+	prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
+	prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
+
+	/* wakeup domain events - bit 1: GPT1, bit5 GPIO */
+	prm_clear_mod_reg_bits(0x4 | 0x1, WKUP_MOD, PM_WKST);
+
+	/* MPU domain wake events */
+	l = prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
+	if (l & 0x01)
+		prm_write_mod_reg(0x01, OCP_MOD,
+				  OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
+	if (l & 0x20)
+		prm_write_mod_reg(0x20, OCP_MOD,
+				  OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
+
+	/* Mask future PRCM-to-MPU interrupts */
+	prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
+}
+
+static int omap2_i2c_active(void)
+{
+	u32 l;
+
+	l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+	return l & (OMAP2420_EN_I2C2 | OMAP2420_EN_I2C1);
+}
+
+static int sti_console_enabled;
+
+static int omap2_allow_mpu_retention(void)
+{
+	u32 l;
+
+	if (atomic_read(&sleep_block))
+		return 0;
+
+	/* Check for MMC, UART2, UART1, McSPI2, McSPI1 and DSS1. */
+	l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+	if (l & (OMAP2420_EN_MMC | OMAP24XX_EN_UART2 |
+		 OMAP24XX_EN_UART1 | OMAP24XX_EN_MCSPI2 |
+		 OMAP24XX_EN_MCSPI1 | OMAP24XX_EN_DSS1))
+		return 0;
+	/* Check for UART3. */
+	l = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+	if (l & OMAP24XX_EN_UART3)
+		return 0;
+	if (sti_console_enabled)
+		return 0;
+
+	return 1;
+}
+
+static void omap2_enter_mpu_retention(void)
+{
+	int only_idle = 0;
+	struct timespec ts_preidle, ts_postidle, ts_idle;
+
+	/* Putting MPU into the WFI state while a transfer is active
+	 * seems to cause the I2C block to timeout. Why? Good question. */
+	if (omap2_i2c_active())
+		return;
+
+	/* The peripherals seem not to be able to wake up the MPU when
+	 * it is in retention mode. */
+	if (omap2_allow_mpu_retention()) {
+		/* REVISIT: These write to reserved bits? */
+		prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
+		prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
+		prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
+
+		/* Try to enter MPU retention */
+		prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) |
+				  OMAP_LOGICRETSTATE,
+				  MPU_MOD, PM_PWSTCTRL);
+	} else {
+		/* Block MPU retention */
+
+		prm_write_mod_reg(OMAP_LOGICRETSTATE, MPU_MOD, PM_PWSTCTRL);
+		only_idle = 1;
+	}
+
+	if (omap2_pm_debug) {
+		omap2_pm_dump(only_idle ? 2 : 1, 0, 0);
+		getnstimeofday(&ts_preidle);
+	}
+
+	omap2_sram_idle();
+
+	if (omap2_pm_debug) {
+		unsigned long long tmp;
+
+		getnstimeofday(&ts_postidle);
+		ts_idle = timespec_sub(ts_postidle, ts_preidle);
+		tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC;
+		omap2_pm_dump(only_idle ? 2 : 1, 1, tmp);
+	}
+}
+
+static int omap2_can_sleep(void)
+{
+	if (!enable_dyn_sleep)
+		return 0;
+	if (omap2_fclks_active())
+		return 0;
+	if (atomic_read(&sleep_block) > 0)
+		return 0;
+	if (osc_ck->usecount > 1)
+		return 0;
+	if (omap_dma_running())
+		return 0;
+
+	return 1;
+}
+
+/*
+ * Note that you can use clock_event_device->min_delta_ns if you want to
+ * avoid reprogramming timer too often when using CONFIG_NO_HZ.
+ */
+static void omap2_pm_idle(void)
+{
+	local_irq_disable();
+	local_fiq_disable();
+
+	if (!omap2_can_sleep()) {
+		if (!atomic_read(&sleep_block) && omap2_irq_pending())
+			goto out;
+		omap2_enter_mpu_retention();
+		goto out;
+	}
+
+	if (omap2_irq_pending())
+		goto out;
+
+	omap2_enter_full_retention();
+
+out:
+	local_fiq_enable();
+	local_irq_enable();
+}
+
+static int omap2_pm_prepare(void)
+{
+	/* We cannot sleep in idle until we have resumed */
+	saved_idle = pm_idle;
+	pm_idle = NULL;
+
+	return 0;
+}
+
+static int omap2_pm_suspend(void)
+{
+	u32 wken_wkup, mir1;
+
+	wken_wkup = prm_read_mod_reg(WKUP_MOD, PM_WKEN);
+	prm_write_mod_reg(wken_wkup & ~OMAP24XX_EN_GPT1, WKUP_MOD, PM_WKEN);
+
+	/* Mask GPT1 */
+	mir1 = omap_readl(0x480fe0a4);
+	omap_writel(1 << 5, 0x480fe0ac);
+
+	omap2_enter_full_retention();
+
+	omap_writel(mir1, 0x480fe0a4);
+	prm_write_mod_reg(wken_wkup, WKUP_MOD, PM_WKEN);
+
+	return 0;
+}
+
+static int omap2_pm_enter(suspend_state_t state)
+{
+	int ret = 0;
+
+	switch (state) {
+	case PM_SUSPEND_STANDBY:
+	case PM_SUSPEND_MEM:
+		ret = omap2_pm_suspend();
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static void omap2_pm_finish(void)
+{
+	pm_idle = saved_idle;
+}
+
+static struct platform_suspend_ops omap_pm_ops = {
+	.prepare	= omap2_pm_prepare,
+	.enter		= omap2_pm_enter,
+	.finish		= omap2_pm_finish,
+	.valid		= suspend_valid_only_mem,
+};
+
+static int _pm_clkdm_enable_hwsup(struct clockdomain *clkdm)
+{
+	omap2_clkdm_allow_idle(clkdm);
+	return 0;
+}
+
+static void __init prcm_setup_regs(void)
+{
+	int i, num_mem_banks;
+	struct powerdomain *pwrdm;
+
+	/* Enable autoidle */
+	prm_write_mod_reg(OMAP24XX_AUTOIDLE, OCP_MOD,
+			  OMAP2_PRCM_SYSCONFIG_OFFSET);
+
+	/* Set all domain wakeup dependencies */
+	prm_write_mod_reg(OMAP_EN_WKUP_MASK, MPU_MOD, PM_WKDEP);
+	prm_write_mod_reg(0, OMAP24XX_DSP_MOD, PM_WKDEP);
+	prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
+	prm_write_mod_reg(0, CORE_MOD, PM_WKDEP);
+	if (cpu_is_omap2430())
+		prm_write_mod_reg(0, OMAP2430_MDM_MOD, PM_WKDEP);
+
+	/*
+	 * Set CORE powerdomain memory banks to retain their contents
+	 * during RETENTION
+	 */
+	num_mem_banks = pwrdm_get_mem_bank_count(core_pwrdm);
+	for (i = 0; i < num_mem_banks; i++)
+		pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET);
+
+	/* Set CORE powerdomain's next power state to RETENTION */
+	pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET);
+
+	/*
+	 * Set MPU powerdomain's next power state to RETENTION;
+	 * preserve logic state during retention
+	 */
+	pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
+	pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
+
+	/* Force-power down DSP, GFX powerdomains */
+
+	pwrdm = clkdm_get_pwrdm(dsp_clkdm);
+	pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
+	omap2_clkdm_sleep(dsp_clkdm);
+
+	pwrdm = clkdm_get_pwrdm(gfx_clkdm);
+	pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
+	omap2_clkdm_sleep(gfx_clkdm);
+
+	/* Enable clockdomain hardware-supervised control for all clkdms */
+	clkdm_for_each(_pm_clkdm_enable_hwsup);
+
+	/* Enable clock autoidle for all domains */
+	cm_write_mod_reg(OMAP24XX_AUTO_CAM |
+			 OMAP24XX_AUTO_MAILBOXES |
+			 OMAP24XX_AUTO_WDT4 |
+			 OMAP2420_AUTO_WDT3 |
+			 OMAP24XX_AUTO_MSPRO |
+			 OMAP2420_AUTO_MMC |
+			 OMAP24XX_AUTO_FAC |
+			 OMAP2420_AUTO_EAC |
+			 OMAP24XX_AUTO_HDQ |
+			 OMAP24XX_AUTO_UART2 |
+			 OMAP24XX_AUTO_UART1 |
+			 OMAP24XX_AUTO_I2C2 |
+			 OMAP24XX_AUTO_I2C1 |
+			 OMAP24XX_AUTO_MCSPI2 |
+			 OMAP24XX_AUTO_MCSPI1 |
+			 OMAP24XX_AUTO_MCBSP2 |
+			 OMAP24XX_AUTO_MCBSP1 |
+			 OMAP24XX_AUTO_GPT12 |
+			 OMAP24XX_AUTO_GPT11 |
+			 OMAP24XX_AUTO_GPT10 |
+			 OMAP24XX_AUTO_GPT9 |
+			 OMAP24XX_AUTO_GPT8 |
+			 OMAP24XX_AUTO_GPT7 |
+			 OMAP24XX_AUTO_GPT6 |
+			 OMAP24XX_AUTO_GPT5 |
+			 OMAP24XX_AUTO_GPT4 |
+			 OMAP24XX_AUTO_GPT3 |
+			 OMAP24XX_AUTO_GPT2 |
+			 OMAP2420_AUTO_VLYNQ |
+			 OMAP24XX_AUTO_DSS,
+			 CORE_MOD, CM_AUTOIDLE1);
+	cm_write_mod_reg(OMAP24XX_AUTO_UART3 |
+			 OMAP24XX_AUTO_SSI |
+			 OMAP24XX_AUTO_USB,
+			 CORE_MOD, CM_AUTOIDLE2);
+	cm_write_mod_reg(OMAP24XX_AUTO_SDRC |
+			 OMAP24XX_AUTO_GPMC |
+			 OMAP24XX_AUTO_SDMA,
+			 CORE_MOD, CM_AUTOIDLE3);
+	cm_write_mod_reg(OMAP24XX_AUTO_PKA |
+			 OMAP24XX_AUTO_AES |
+			 OMAP24XX_AUTO_RNG |
+			 OMAP24XX_AUTO_SHA |
+			 OMAP24XX_AUTO_DES,
+			 CORE_MOD, OMAP24XX_CM_AUTOIDLE4);
+
+	cm_write_mod_reg(OMAP2420_AUTO_DSP_IPI, OMAP24XX_DSP_MOD, CM_AUTOIDLE);
+
+	/* Put DPLL and both APLLs into autoidle mode */
+	cm_write_mod_reg((0x03 << OMAP24XX_AUTO_DPLL_SHIFT) |
+			 (0x03 << OMAP24XX_AUTO_96M_SHIFT) |
+			 (0x03 << OMAP24XX_AUTO_54M_SHIFT),
+			 PLL_MOD, CM_AUTOIDLE);
+
+	cm_write_mod_reg(OMAP24XX_AUTO_OMAPCTRL |
+			 OMAP24XX_AUTO_WDT1 |
+			 OMAP24XX_AUTO_MPU_WDT |
+			 OMAP24XX_AUTO_GPIOS |
+			 OMAP24XX_AUTO_32KSYNC |
+			 OMAP24XX_AUTO_GPT1,
+			 WKUP_MOD, CM_AUTOIDLE);
+
+	/* REVISIT: Configure number of 32 kHz clock cycles for sys_clk
+	 * stabilisation */
+	prm_write_mod_reg(15 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
+			  OMAP2_PRCM_CLKSSETUP_OFFSET);
+
+	/* Configure automatic voltage transition */
+	prm_write_mod_reg(2 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
+			  OMAP2_PRCM_VOLTSETUP_OFFSET);
+	prm_write_mod_reg(OMAP24XX_AUTO_EXTVOLT |
+			  (0x1 << OMAP24XX_SETOFF_LEVEL_SHIFT) |
+			  OMAP24XX_MEMRETCTRL |
+			  (0x1 << OMAP24XX_SETRET_LEVEL_SHIFT) |
+			  (0x0 << OMAP24XX_VOLT_LEVEL_SHIFT),
+			  OMAP24XX_GR_MOD, OMAP2_PRCM_VOLTCTRL_OFFSET);
+
+	/* Enable wake-up events */
+	prm_write_mod_reg(OMAP24XX_EN_GPIOS | OMAP24XX_EN_GPT1,
+			  WKUP_MOD, PM_WKEN);
+}
+
+int __init omap2_pm_init(void)
+{
+	u32 l;
+
+	printk(KERN_INFO "Power Management for OMAP2 initializing\n");
+	l = prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_REVISION_OFFSET);
+	printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
+
+	/* Look up important powerdomains, clockdomains */
+
+	mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
+	if (!mpu_pwrdm)
+		pr_err("PM: mpu_pwrdm not found\n");
+
+	core_pwrdm = pwrdm_lookup("core_pwrdm");
+	if (!core_pwrdm)
+		pr_err("PM: core_pwrdm not found\n");
+
+	dsp_clkdm = clkdm_lookup("dsp_clkdm");
+	if (!dsp_clkdm)
+		pr_err("PM: mpu_clkdm not found\n");
+
+	gfx_clkdm = clkdm_lookup("gfx_clkdm");
+	if (!gfx_clkdm)
+		pr_err("PM: gfx_clkdm not found\n");
+
+
+	osc_ck = clk_get(NULL, "osc_ck");
+	if (IS_ERR(osc_ck)) {
+		printk(KERN_ERR "could not get osc_ck\n");
+		return -ENODEV;
+	}
+
+	if (cpu_is_omap242x()) {
+		emul_ck = clk_get(NULL, "emul_ck");
+		if (IS_ERR(emul_ck)) {
+			printk(KERN_ERR "could not get emul_ck\n");
+			clk_put(osc_ck);
+			return -ENODEV;
+		}
+	}
+
+	prcm_setup_regs();
+
+	/* Hack to prevent MPU retention when STI console is enabled. */
+	{
+		const struct omap_sti_console_config *sti;
+
+		sti = omap_get_config(OMAP_TAG_STI_CONSOLE,
+				      struct omap_sti_console_config);
+		if (sti != NULL && sti->enable)
+			sti_console_enabled = 1;
+	}
+
+	/*
+	 * We copy the assembler sleep/wakeup routines to SRAM.
+	 * These routines need to be in SRAM as that's the only
+	 * memory the MPU can see when it wakes up.
+	 */
+	if (cpu_is_omap24xx()) {
+		omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend,
+						 omap24xx_idle_loop_suspend_sz);
+
+		omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend,
+						    omap24xx_cpu_suspend_sz);
+	}
+
+	suspend_set_ops(&omap_pm_ops);
+	pm_idle = omap2_pm_idle;
+
+	return 0;
+}
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
new file mode 100644
index 0000000..0fb6bec
--- /dev/null
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -0,0 +1,607 @@
+/*
+ * OMAP3 Power Management Routines
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ * Jouni Hogander
+ *
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * Based on pm.c for omap1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/pm.h>
+#include <linux/suspend.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/err.h>
+
+#include <mach/gpio.h>
+#include <mach/sram.h>
+#include <mach/clockdomain.h>
+#include <mach/powerdomain.h>
+#include <mach/control.h>
+
+#include "cm.h"
+#include "cm-regbits-34xx.h"
+#include "prm-regbits-34xx.h"
+
+#include "prm.h"
+#include "pm.h"
+
+struct power_state {
+	struct powerdomain *pwrdm;
+	u32 next_state;
+	u32 saved_state;
+	struct list_head node;
+};
+
+static LIST_HEAD(pwrst_list);
+
+static void (*_omap_sram_idle)(u32 *addr, int save_state);
+
+static void (*saved_idle)(void);
+
+static struct powerdomain *mpu_pwrdm;
+
+/* PRCM Interrupt Handler for wakeups */
+static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
+{
+	u32 wkst, irqstatus_mpu;
+	u32 fclk, iclk;
+
+	/* WKUP */
+	wkst = prm_read_mod_reg(WKUP_MOD, PM_WKST);
+	if (wkst) {
+		iclk = cm_read_mod_reg(WKUP_MOD, CM_ICLKEN);
+		fclk = cm_read_mod_reg(WKUP_MOD, CM_FCLKEN);
+		cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_ICLKEN);
+		cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_FCLKEN);
+		prm_write_mod_reg(wkst, WKUP_MOD, PM_WKST);
+		while (prm_read_mod_reg(WKUP_MOD, PM_WKST))
+			cpu_relax();
+		cm_write_mod_reg(iclk, WKUP_MOD, CM_ICLKEN);
+		cm_write_mod_reg(fclk, WKUP_MOD, CM_FCLKEN);
+	}
+
+	/* CORE */
+	wkst = prm_read_mod_reg(CORE_MOD, PM_WKST1);
+	if (wkst) {
+		iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN1);
+		fclk = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+		cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN1);
+		cm_set_mod_reg_bits(wkst, CORE_MOD, CM_FCLKEN1);
+		prm_write_mod_reg(wkst, CORE_MOD, PM_WKST1);
+		while (prm_read_mod_reg(CORE_MOD, PM_WKST1))
+			cpu_relax();
+		cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN1);
+		cm_write_mod_reg(fclk, CORE_MOD, CM_FCLKEN1);
+	}
+	wkst = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3);
+	if (wkst) {
+		iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN3);
+		fclk = cm_read_mod_reg(CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
+		cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN3);
+		cm_set_mod_reg_bits(wkst, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
+		prm_write_mod_reg(wkst, CORE_MOD, OMAP3430ES2_PM_WKST3);
+		while (prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3))
+			cpu_relax();
+		cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN3);
+		cm_write_mod_reg(fclk, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
+	}
+
+	/* PER */
+	wkst = prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST);
+	if (wkst) {
+		iclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_ICLKEN);
+		fclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN);
+		cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_ICLKEN);
+		cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_FCLKEN);
+		prm_write_mod_reg(wkst, OMAP3430_PER_MOD, PM_WKST);
+		while (prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST))
+			cpu_relax();
+		cm_write_mod_reg(iclk, OMAP3430_PER_MOD, CM_ICLKEN);
+		cm_write_mod_reg(fclk, OMAP3430_PER_MOD, CM_FCLKEN);
+	}
+
+	if (omap_rev() > OMAP3430_REV_ES1_0) {
+		/* USBHOST */
+		wkst = prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKST);
+		if (wkst) {
+			iclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+					       CM_ICLKEN);
+			fclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+					       CM_FCLKEN);
+			cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
+					    CM_ICLKEN);
+			cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
+					    CM_FCLKEN);
+			prm_write_mod_reg(wkst, OMAP3430ES2_USBHOST_MOD,
+					  PM_WKST);
+			while (prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+						PM_WKST))
+				cpu_relax();
+			cm_write_mod_reg(iclk, OMAP3430ES2_USBHOST_MOD,
+					 CM_ICLKEN);
+			cm_write_mod_reg(fclk, OMAP3430ES2_USBHOST_MOD,
+					 CM_FCLKEN);
+		}
+	}
+
+	irqstatus_mpu = prm_read_mod_reg(OCP_MOD,
+					 OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+	prm_write_mod_reg(irqstatus_mpu, OCP_MOD,
+			  OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+
+	while (prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET))
+		cpu_relax();
+
+	return IRQ_HANDLED;
+}
+
+static void omap_sram_idle(void)
+{
+	/* Variable to tell what needs to be saved and restored
+	 * in omap_sram_idle*/
+	/* save_state = 0 => Nothing to save and restored */
+	/* save_state = 1 => Only L1 and logic lost */
+	/* save_state = 2 => Only L2 lost */
+	/* save_state = 3 => L1, L2 and logic lost */
+	int save_state = 0, mpu_next_state;
+
+	if (!_omap_sram_idle)
+		return;
+
+	mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
+	switch (mpu_next_state) {
+	case PWRDM_POWER_RET:
+		/* No need to save context */
+		save_state = 0;
+		break;
+	default:
+		/* Invalid state */
+		printk(KERN_ERR "Invalid mpu state in sram_idle\n");
+		return;
+	}
+	omap2_gpio_prepare_for_retention();
+
+	_omap_sram_idle(NULL, save_state);
+
+	omap2_gpio_resume_after_retention();
+}
+
+/*
+ * Check if functional clocks are enabled before entering
+ * sleep. This function could be behind CONFIG_PM_DEBUG
+ * when all drivers are configuring their sysconfig registers
+ * properly and using their clocks properly.
+ */
+static int omap3_fclks_active(void)
+{
+	u32 fck_core1 = 0, fck_core3 = 0, fck_sgx = 0, fck_dss = 0,
+		fck_cam = 0, fck_per = 0, fck_usbhost = 0;
+
+	fck_core1 = cm_read_mod_reg(CORE_MOD,
+				    CM_FCLKEN1);
+	if (omap_rev() > OMAP3430_REV_ES1_0) {
+		fck_core3 = cm_read_mod_reg(CORE_MOD,
+					    OMAP3430ES2_CM_FCLKEN3);
+		fck_sgx = cm_read_mod_reg(OMAP3430ES2_SGX_MOD,
+					  CM_FCLKEN);
+		fck_usbhost = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+					      CM_FCLKEN);
+	} else
+		fck_sgx = cm_read_mod_reg(GFX_MOD,
+					  OMAP3430ES2_CM_FCLKEN3);
+	fck_dss = cm_read_mod_reg(OMAP3430_DSS_MOD,
+				  CM_FCLKEN);
+	fck_cam = cm_read_mod_reg(OMAP3430_CAM_MOD,
+				  CM_FCLKEN);
+	fck_per = cm_read_mod_reg(OMAP3430_PER_MOD,
+				  CM_FCLKEN);
+	if (fck_core1 | fck_core3 | fck_sgx | fck_dss |
+	    fck_cam | fck_per | fck_usbhost)
+		return 1;
+	return 0;
+}
+
+static int omap3_can_sleep(void)
+{
+	if (!enable_dyn_sleep)
+		return 0;
+	if (omap3_fclks_active())
+		return 0;
+	if (atomic_read(&sleep_block) > 0)
+		return 0;
+	return 1;
+}
+
+/* This sets pwrdm state (other than mpu & core. Currently only ON &
+ * RET are supported. Function is assuming that clkdm doesn't have
+ * hw_sup mode enabled. */
+static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
+{
+	u32 cur_state;
+	int sleep_switch = 0;
+	int ret = 0;
+
+	if (pwrdm == NULL || IS_ERR(pwrdm))
+		return -EINVAL;
+
+	while (!(pwrdm->pwrsts & (1 << state))) {
+		if (state == PWRDM_POWER_OFF)
+			return ret;
+		state--;
+	}
+
+	cur_state = pwrdm_read_next_pwrst(pwrdm);
+	if (cur_state == state)
+		return ret;
+
+	if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
+		omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
+		sleep_switch = 1;
+		pwrdm_wait_transition(pwrdm);
+	}
+
+	ret = pwrdm_set_next_pwrst(pwrdm, state);
+	if (ret) {
+		printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
+		       pwrdm->name);
+		goto err;
+	}
+
+	if (sleep_switch) {
+		omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
+		pwrdm_wait_transition(pwrdm);
+	}
+
+err:
+	return ret;
+}
+
+static void omap3_pm_idle(void)
+{
+	local_irq_disable();
+	local_fiq_disable();
+
+	if (!omap3_can_sleep())
+		goto out;
+
+	if (omap_irq_pending())
+		goto out;
+
+	omap_sram_idle();
+
+out:
+	local_fiq_enable();
+	local_irq_enable();
+}
+
+static int omap3_pm_prepare(void)
+{
+	saved_idle = pm_idle;
+	pm_idle = NULL;
+	return 0;
+}
+
+static int omap3_pm_suspend(void)
+{
+	struct power_state *pwrst;
+	int state, ret = 0;
+
+	/* Read current next_pwrsts */
+	list_for_each_entry(pwrst, &pwrst_list, node)
+		pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
+	/* Set ones wanted by suspend */
+	list_for_each_entry(pwrst, &pwrst_list, node) {
+		if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
+			goto restore;
+		if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
+			goto restore;
+	}
+
+	omap_sram_idle();
+
+restore:
+	/* Restore next_pwrsts */
+	list_for_each_entry(pwrst, &pwrst_list, node) {
+		set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
+		state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
+		if (state > pwrst->next_state) {
+			printk(KERN_INFO "Powerdomain (%s) didn't enter "
+			       "target state %d\n",
+			       pwrst->pwrdm->name, pwrst->next_state);
+			ret = -1;
+		}
+	}
+	if (ret)
+		printk(KERN_ERR "Could not enter target state in pm_suspend\n");
+	else
+		printk(KERN_INFO "Successfully put all powerdomains "
+		       "to target state\n");
+
+	return ret;
+}
+
+static int omap3_pm_enter(suspend_state_t state)
+{
+	int ret = 0;
+
+	switch (state) {
+	case PM_SUSPEND_STANDBY:
+	case PM_SUSPEND_MEM:
+		ret = omap3_pm_suspend();
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static void omap3_pm_finish(void)
+{
+	pm_idle = saved_idle;
+}
+
+static struct platform_suspend_ops omap_pm_ops = {
+	.prepare	= omap3_pm_prepare,
+	.enter		= omap3_pm_enter,
+	.finish		= omap3_pm_finish,
+	.valid		= suspend_valid_only_mem,
+};
+
+static void __init prcm_setup_regs(void)
+{
+	/* reset modem */
+	prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON |
+			  OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST,
+			  CORE_MOD, RM_RSTCTRL);
+	prm_write_mod_reg(0, CORE_MOD, RM_RSTCTRL);
+
+	/* XXX Reset all wkdeps. This should be done when initializing
+	 * powerdomains */
+	prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
+	prm_write_mod_reg(0, MPU_MOD, PM_WKDEP);
+	prm_write_mod_reg(0, OMAP3430_DSS_MOD, PM_WKDEP);
+	prm_write_mod_reg(0, OMAP3430_NEON_MOD, PM_WKDEP);
+	prm_write_mod_reg(0, OMAP3430_CAM_MOD, PM_WKDEP);
+	prm_write_mod_reg(0, OMAP3430_PER_MOD, PM_WKDEP);
+	if (omap_rev() > OMAP3430_REV_ES1_0) {
+		prm_write_mod_reg(0, OMAP3430ES2_SGX_MOD, PM_WKDEP);
+		prm_write_mod_reg(0, OMAP3430ES2_USBHOST_MOD, PM_WKDEP);
+	} else
+		prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
+
+	/*
+	 * Enable interface clock autoidle for all modules.
+	 * Note that in the long run this should be done by clockfw
+	 */
+	cm_write_mod_reg(
+		OMAP3430ES2_AUTO_MMC3 |
+		OMAP3430ES2_AUTO_ICR |
+		OMAP3430_AUTO_AES2 |
+		OMAP3430_AUTO_SHA12 |
+		OMAP3430_AUTO_DES2 |
+		OMAP3430_AUTO_MMC2 |
+		OMAP3430_AUTO_MMC1 |
+		OMAP3430_AUTO_MSPRO |
+		OMAP3430_AUTO_HDQ |
+		OMAP3430_AUTO_MCSPI4 |
+		OMAP3430_AUTO_MCSPI3 |
+		OMAP3430_AUTO_MCSPI2 |
+		OMAP3430_AUTO_MCSPI1 |
+		OMAP3430_AUTO_I2C3 |
+		OMAP3430_AUTO_I2C2 |
+		OMAP3430_AUTO_I2C1 |
+		OMAP3430_AUTO_UART2 |
+		OMAP3430_AUTO_UART1 |
+		OMAP3430_AUTO_GPT11 |
+		OMAP3430_AUTO_GPT10 |
+		OMAP3430_AUTO_MCBSP5 |
+		OMAP3430_AUTO_MCBSP1 |
+		OMAP3430ES1_AUTO_FAC | /* This is es1 only */
+		OMAP3430_AUTO_MAILBOXES |
+		OMAP3430_AUTO_OMAPCTRL |
+		OMAP3430ES1_AUTO_FSHOSTUSB |
+		OMAP3430_AUTO_HSOTGUSB |
+		OMAP3430ES1_AUTO_D2D | /* This is es1 only */
+		OMAP3430_AUTO_SSI,
+		CORE_MOD, CM_AUTOIDLE1);
+
+	cm_write_mod_reg(
+		OMAP3430_AUTO_PKA |
+		OMAP3430_AUTO_AES1 |
+		OMAP3430_AUTO_RNG |
+		OMAP3430_AUTO_SHA11 |
+		OMAP3430_AUTO_DES1,
+		CORE_MOD, CM_AUTOIDLE2);
+
+	if (omap_rev() > OMAP3430_REV_ES1_0) {
+		cm_write_mod_reg(
+			OMAP3430ES2_AUTO_USBTLL,
+			CORE_MOD, CM_AUTOIDLE3);
+	}
+
+	cm_write_mod_reg(
+		OMAP3430_AUTO_WDT2 |
+		OMAP3430_AUTO_WDT1 |
+		OMAP3430_AUTO_GPIO1 |
+		OMAP3430_AUTO_32KSYNC |
+		OMAP3430_AUTO_GPT12 |
+		OMAP3430_AUTO_GPT1 ,
+		WKUP_MOD, CM_AUTOIDLE);
+
+	cm_write_mod_reg(
+		OMAP3430_AUTO_DSS,
+		OMAP3430_DSS_MOD,
+		CM_AUTOIDLE);
+
+	cm_write_mod_reg(
+		OMAP3430_AUTO_CAM,
+		OMAP3430_CAM_MOD,
+		CM_AUTOIDLE);
+
+	cm_write_mod_reg(
+		OMAP3430_AUTO_GPIO6 |
+		OMAP3430_AUTO_GPIO5 |
+		OMAP3430_AUTO_GPIO4 |
+		OMAP3430_AUTO_GPIO3 |
+		OMAP3430_AUTO_GPIO2 |
+		OMAP3430_AUTO_WDT3 |
+		OMAP3430_AUTO_UART3 |
+		OMAP3430_AUTO_GPT9 |
+		OMAP3430_AUTO_GPT8 |
+		OMAP3430_AUTO_GPT7 |
+		OMAP3430_AUTO_GPT6 |
+		OMAP3430_AUTO_GPT5 |
+		OMAP3430_AUTO_GPT4 |
+		OMAP3430_AUTO_GPT3 |
+		OMAP3430_AUTO_GPT2 |
+		OMAP3430_AUTO_MCBSP4 |
+		OMAP3430_AUTO_MCBSP3 |
+		OMAP3430_AUTO_MCBSP2,
+		OMAP3430_PER_MOD,
+		CM_AUTOIDLE);
+
+	if (omap_rev() > OMAP3430_REV_ES1_0) {
+		cm_write_mod_reg(
+			OMAP3430ES2_AUTO_USBHOST,
+			OMAP3430ES2_USBHOST_MOD,
+			CM_AUTOIDLE);
+	}
+
+	/*
+	 * Set all plls to autoidle. This is needed until autoidle is
+	 * enabled by clockfw
+	 */
+	cm_write_mod_reg(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT,
+			 OMAP3430_IVA2_MOD, CM_AUTOIDLE2);
+	cm_write_mod_reg(1 << OMAP3430_AUTO_MPU_DPLL_SHIFT,
+			 MPU_MOD,
+			 CM_AUTOIDLE2);
+	cm_write_mod_reg((1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT) |
+			 (1 << OMAP3430_AUTO_CORE_DPLL_SHIFT),
+			 PLL_MOD,
+			 CM_AUTOIDLE);
+	cm_write_mod_reg(1 << OMAP3430ES2_AUTO_PERIPH2_DPLL_SHIFT,
+			 PLL_MOD,
+			 CM_AUTOIDLE2);
+
+	/*
+	 * Enable control of expternal oscillator through
+	 * sys_clkreq. In the long run clock framework should
+	 * take care of this.
+	 */
+	prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK,
+			     1 << OMAP_AUTOEXTCLKMODE_SHIFT,
+			     OMAP3430_GR_MOD,
+			     OMAP3_PRM_CLKSRC_CTRL_OFFSET);
+
+	/* setup wakup source */
+	prm_write_mod_reg(OMAP3430_EN_IO | OMAP3430_EN_GPIO1 |
+			  OMAP3430_EN_GPT1 | OMAP3430_EN_GPT12,
+			  WKUP_MOD, PM_WKEN);
+	/* No need to write EN_IO, that is always enabled */
+	prm_write_mod_reg(OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1 |
+			  OMAP3430_EN_GPT12,
+			  WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
+	/* For some reason IO doesn't generate wakeup event even if
+	 * it is selected to mpu wakeup goup */
+	prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
+			  OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
+}
+
+static int __init pwrdms_setup(struct powerdomain *pwrdm)
+{
+	struct power_state *pwrst;
+
+	if (!pwrdm->pwrsts)
+		return 0;
+
+	pwrst = kmalloc(sizeof(struct power_state), GFP_KERNEL);
+	if (!pwrst)
+		return -ENOMEM;
+	pwrst->pwrdm = pwrdm;
+	pwrst->next_state = PWRDM_POWER_RET;
+	list_add(&pwrst->node, &pwrst_list);
+
+	if (pwrdm_has_hdwr_sar(pwrdm))
+		pwrdm_enable_hdwr_sar(pwrdm);
+
+	return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
+}
+
+/*
+ * Enable hw supervised mode for all clockdomains if it's
+ * supported. Initiate sleep transition for other clockdomains, if
+ * they are not used
+ */
+static int __init clkdms_setup(struct clockdomain *clkdm)
+{
+	if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
+		omap2_clkdm_allow_idle(clkdm);
+	else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
+		 atomic_read(&clkdm->usecount) == 0)
+		omap2_clkdm_sleep(clkdm);
+	return 0;
+}
+
+int __init omap3_pm_init(void)
+{
+	struct power_state *pwrst, *tmp;
+	int ret;
+
+	printk(KERN_ERR "Power Management for TI OMAP3.\n");
+
+	/* XXX prcm_setup_regs needs to be before enabling hw
+	 * supervised mode for powerdomains */
+	prcm_setup_regs();
+
+	ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
+			  (irq_handler_t)prcm_interrupt_handler,
+			  IRQF_DISABLED, "prcm", NULL);
+	if (ret) {
+		printk(KERN_ERR "request_irq failed to register for 0x%x\n",
+		       INT_34XX_PRCM_MPU_IRQ);
+		goto err1;
+	}
+
+	ret = pwrdm_for_each(pwrdms_setup);
+	if (ret) {
+		printk(KERN_ERR "Failed to setup powerdomains\n");
+		goto err2;
+	}
+
+	(void) clkdm_for_each(clkdms_setup);
+
+	mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
+	if (mpu_pwrdm == NULL) {
+		printk(KERN_ERR "Failed to get mpu_pwrdm\n");
+		goto err2;
+	}
+
+	_omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
+					 omap34xx_cpu_suspend_sz);
+
+	suspend_set_ops(&omap_pm_ops);
+
+	pm_idle = omap3_pm_idle;
+
+err1:
+	return ret;
+err2:
+	free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
+	list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) {
+		list_del(&pwrst->node);
+		kfree(pwrst);
+	}
+	return ret;
+}
diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
index 812d50e..cb1ae84 100644
--- a/arch/arm/mach-omap2/prcm-common.h
+++ b/arch/arm/mach-omap2/prcm-common.h
@@ -276,6 +276,8 @@
 /* CM_FCLKEN_WKUP, CM_ICLKEN_WKUP, PM_WKEN_WKUP shared bits */
 #define OMAP3430_EN_GPIO1				(1 << 3)
 #define OMAP3430_EN_GPIO1_SHIFT				3
+#define OMAP3430_EN_GPT12				(1 << 1)
+#define OMAP3430_EN_GPT12_SHIFT				1
 #define OMAP3430_EN_GPT1				(1 << 0)
 #define OMAP3430_EN_GPT1_SHIFT				0
 
diff --git a/arch/arm/mach-omap2/sdrc.c b/arch/arm/mach-omap2/sdrc.c
index 2a30060..993fd25 100644
--- a/arch/arm/mach-omap2/sdrc.c
+++ b/arch/arm/mach-omap2/sdrc.c
@@ -56,9 +56,12 @@ struct omap_sdrc_params *omap2_sdrc_get_params(unsigned long r)
 {
 	struct omap_sdrc_params *sp;
 
+	if (!sdrc_init_params)
+		return NULL;
+
 	sp = sdrc_init_params;
 
-	while (sp->rate != r)
+	while (sp->rate && sp->rate != r)
 		sp++;
 
 	if (!sp->rate)
diff --git a/arch/arm/mach-omap2/sleep24xx.S b/arch/arm/mach-omap2/sleep24xx.S
index bf9e961..130aadb 100644
--- a/arch/arm/mach-omap2/sleep24xx.S
+++ b/arch/arm/mach-omap2/sleep24xx.S
@@ -28,7 +28,6 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <mach/io.h>
-#include <mach/pm.h>
 
 #include <mach/omap24xx.h>
 
diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S
new file mode 100644
index 0000000..ce29d65
--- /dev/null
+++ b/arch/arm/mach-omap2/sleep34xx.S
@@ -0,0 +1,543 @@
+/*
+ * linux/arch/arm/mach-omap2/sleep.S
+ *
+ * (C) Copyright 2007
+ * Texas Instruments
+ * Karthik Dasu <karthik-dp@ti.com>
+ *
+ * (C) Copyright 2004
+ * Texas Instruments, <www.ti.com>
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <mach/io.h>
+#include <mach/control.h>
+
+#include "prm.h"
+#include "sdrc.h"
+
+#define PM_PREPWSTST_CORE_V	OMAP34XX_PRM_REGADDR(CORE_MOD, \
+				OMAP3430_PM_PREPWSTST)
+#define PM_PREPWSTST_MPU_V	OMAP34XX_PRM_REGADDR(MPU_MOD, \
+				OMAP3430_PM_PREPWSTST)
+#define PM_PWSTCTRL_MPU_P	OMAP34XX_PRM_REGADDR(MPU_MOD, PM_PWSTCTRL)
+#define SCRATCHPAD_MEM_OFFS	0x310 /* Move this as correct place is
+				       * available */
+#define SCRATCHPAD_BASE_P	OMAP343X_CTRL_REGADDR(\
+				OMAP343X_CONTROL_MEM_WKUP +\
+				SCRATCHPAD_MEM_OFFS)
+#define SDRC_POWER_V		OMAP34XX_SDRC_REGADDR(SDRC_POWER)
+
+	.text
+/* Function call to get the restore pointer for resume from OFF */
+ENTRY(get_restore_pointer)
+        stmfd   sp!, {lr}     @ save registers on stack
+	adr	r0, restore
+        ldmfd   sp!, {pc}     @ restore regs and return
+ENTRY(get_restore_pointer_sz)
+        .word   . - get_restore_pointer_sz
+/*
+ * Forces OMAP into idle state
+ *
+ * omap34xx_suspend() - This bit of code just executes the WFI
+ * for normal idles.
+ *
+ * Note: This code get's copied to internal SRAM at boot. When the OMAP
+ *	 wakes up it continues execution at the point it went to sleep.
+ */
+ENTRY(omap34xx_cpu_suspend)
+	stmfd	sp!, {r0-r12, lr}		@ save registers on stack
+loop:
+	/*b	loop*/	@Enable to debug by stepping through code
+	/* r0 contains restore pointer in sdram */
+	/* r1 contains information about saving context */
+	ldr     r4, sdrc_power          @ read the SDRC_POWER register
+	ldr     r5, [r4]                @ read the contents of SDRC_POWER
+	orr     r5, r5, #0x40           @ enable self refresh on idle req
+	str     r5, [r4]                @ write back to SDRC_POWER register
+
+	cmp	r1, #0x0
+	/* If context save is required, do that and execute wfi */
+	bne	save_context_wfi
+	/* Data memory barrier and Data sync barrier */
+	mov	r1, #0
+	mcr	p15, 0, r1, c7, c10, 4
+	mcr	p15, 0, r1, c7, c10, 5
+
+	wfi				@ wait for interrupt
+
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	bl i_dll_wait
+
+	ldmfd	sp!, {r0-r12, pc}		@ restore regs and return
+restore:
+	/* b restore*/ 	@ Enable to debug restore code
+        /* Check what was the reason for mpu reset and store the reason in r9*/
+        /* 1 - Only L1 and logic lost */
+        /* 2 - Only L2 lost - In this case, we wont be here */
+        /* 3 - Both L1 and L2 lost */
+	ldr     r1, pm_pwstctrl_mpu
+	ldr	r2, [r1]
+	and     r2, r2, #0x3
+	cmp     r2, #0x0	@ Check if target power state was OFF or RET
+        moveq   r9, #0x3        @ MPU OFF => L1 and L2 lost
+	movne	r9, #0x1	@ Only L1 and L2 lost => avoid L2 invalidation
+	bne	logic_l1_restore
+	/* Execute smi to invalidate L2 cache */
+	mov r12, #0x1                         @ set up to invalide L2
+smi:    .word 0xE1600070                @ Call SMI monitor (smieq)
+logic_l1_restore:
+	mov	r1, #0
+	/* Invalidate all instruction caches to PoU
+	 * and flush branch target cache */
+	mcr	p15, 0, r1, c7, c5, 0
+
+	ldr	r4, scratchpad_base
+	ldr	r3, [r4,#0xBC]
+	ldmia	r3!, {r4-r6}
+	mov	sp, r4
+	msr	spsr_cxsf, r5
+	mov	lr, r6
+
+	ldmia	r3!, {r4-r9}
+	/* Coprocessor access Control Register */
+	mcr p15, 0, r4, c1, c0, 2
+
+	/* TTBR0 */
+	MCR p15, 0, r5, c2, c0, 0
+	/* TTBR1 */
+	MCR p15, 0, r6, c2, c0, 1
+	/* Translation table base control register */
+	MCR p15, 0, r7, c2, c0, 2
+	/*domain access Control Register */
+	MCR p15, 0, r8, c3, c0, 0
+	/* data fault status Register */
+	MCR p15, 0, r9, c5, c0, 0
+
+	ldmia  r3!,{r4-r8}
+	/* instruction fault status Register */
+	MCR p15, 0, r4, c5, c0, 1
+	/*Data Auxiliary Fault Status Register */
+	MCR p15, 0, r5, c5, c1, 0
+	/*Instruction Auxiliary Fault Status Register*/
+	MCR p15, 0, r6, c5, c1, 1
+	/*Data Fault Address Register */
+	MCR p15, 0, r7, c6, c0, 0
+	/*Instruction Fault Address Register*/
+	MCR p15, 0, r8, c6, c0, 2
+	ldmia  r3!,{r4-r7}
+
+	/* user r/w thread and process ID */
+	MCR p15, 0, r4, c13, c0, 2
+	/* user ro thread and process ID */
+	MCR p15, 0, r5, c13, c0, 3
+	/*Privileged only thread and process ID */
+	MCR p15, 0, r6, c13, c0, 4
+	/* cache size selection */
+	MCR p15, 2, r7, c0, c0, 0
+	ldmia  r3!,{r4-r8}
+	/* Data TLB lockdown registers */
+	MCR p15, 0, r4, c10, c0, 0
+	/* Instruction TLB lockdown registers */
+	MCR p15, 0, r5, c10, c0, 1
+	/* Secure or Nonsecure Vector Base Address */
+	MCR p15, 0, r6, c12, c0, 0
+	/* FCSE PID */
+	MCR p15, 0, r7, c13, c0, 0
+	/* Context PID */
+	MCR p15, 0, r8, c13, c0, 1
+
+	ldmia  r3!,{r4-r5}
+	/* primary memory remap register */
+	MCR p15, 0, r4, c10, c2, 0
+	/*normal memory remap register */
+	MCR p15, 0, r5, c10, c2, 1
+
+	/* Restore registers for other modes from SDRAM */
+	/* Save current mode */
+	mrs	r7, cpsr
+
+	/* FIQ mode */
+	bic	r0, r7, #0x1F
+	orr	r0, r0, #0x11
+	msr	cpsr, r0
+	ldmia	r3!, {r8-r12}
+	/* load the SP and LR from SDRAM */
+	ldmia  r3!,{r4-r6}
+	mov    sp, r4	/*update the SP */
+	mov    lr, r5	/*update the LR */
+	msr    spsr, r6	/*update the SPSR*/
+
+	/* IRQ mode */
+	bic    r0, r7, #0x1F
+	orr    r0, r0, #0x12
+	msr    cpsr, r0	/*go into IRQ mode*/
+	ldmia  r3!,{r4-r6}	/*load the SP and LR from SDRAM*/
+	mov    sp, r4	/*update the SP */
+	mov    lr, r5	/*update the LR */
+	msr    spsr, r6	/*update the SPSR */
+
+	/* ABORT mode */
+	bic    r0, r7, #0x1F
+	orr    r0, r0, #0x17
+	msr    cpsr, r0	/* go into ABORT mode */
+	ldmia  r3!,{r4-r6}	/*load the SP and LR from SDRAM */
+	mov    sp, r4		/*update the SP */
+	mov    lr, r5		/*update the LR */
+	msr    spsr, r6		/*update the SPSR */
+
+	/* UNDEEF mode */
+	bic    r0, r7, #0x1F
+	orr    r0, r0, #0x1B
+	msr    cpsr, r0		/*go into UNDEF mode */
+	ldmia  r3!,{r4-r6}	/*load the SP and LR from SDRAM */
+	mov    sp, r4		/*update the SP*/
+	mov    lr, r5		/*update the LR*/
+	msr    spsr, r6		/*update the SPSR*/
+
+	/* SYSTEM (USER) mode */
+	bic    r0, r7, #0x1F
+	orr    r0, r0, #0x1F
+	msr    cpsr, r0		/*go into USR mode */
+	ldmia  r3!,{r4-r6}	/*load the SP and LR from SDRAM*/
+	mov    sp, r4		/*update the SP */
+	mov    lr, r5		/*update the LR */
+	msr    spsr, r6		/*update the SPSR */
+	msr    cpsr, r7		/*back to original mode*/
+
+	/* Restore cpsr */
+	ldmia	r3!,{r4}	/*load CPSR from SDRAM*/
+	msr	cpsr, r4	/*store cpsr */
+
+	/* Enabling MMU here */
+	mrc	p15, 0, r7, c2, c0, 2 /* Read TTBRControl */
+	/* Extract N (0:2) bits and decide whether to use TTBR0 or TTBR1*/
+	and	r7, #0x7
+	cmp	r7, #0x0
+	beq	usettbr0
+ttbr_error:
+	/* More work needs to be done to support N[0:2] value other than 0
+	* So looping here so that the error can be detected
+	*/
+	b	ttbr_error
+usettbr0:
+	mrc	p15, 0, r2, c2, c0, 0
+	ldr	r5, ttbrbit_mask
+	and	r2, r5
+	mov	r4, pc
+	ldr	r5, table_index_mask
+	and	r4, r5 /* r4 = 31 to 20 bits of pc */
+	/* Extract the value to be written to table entry */
+	ldr	r1, table_entry
+	add	r1, r1, r4 /* r1 has value to be written to table entry*/
+	/* Getting the address of table entry to modify */
+	lsr	r4, #18
+	add	r2, r4 /* r2 has the location which needs to be modified */
+	/* Storing previous entry of location being modified */
+	ldr	r5, scratchpad_base
+	ldr	r4, [r2]
+	str	r4, [r5, #0xC0]
+	/* Modify the table entry */
+	str	r1, [r2]
+	/* Storing address of entry being modified
+	 * - will be restored after enabling MMU */
+	ldr	r5, scratchpad_base
+	str	r2, [r5, #0xC4]
+
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 4	@ Flush prefetch buffer
+	mcr	p15, 0, r0, c7, c5, 6	@ Invalidate branch predictor array
+	mcr	p15, 0, r0, c8, c5, 0	@ Invalidate instruction TLB
+	mcr	p15, 0, r0, c8, c6, 0	@ Invalidate data TLB
+	/* Restore control register  but dont enable caches here*/
+	/* Caches will be enabled after restoring MMU table entry */
+	ldmia	r3!, {r4}
+	/* Store previous value of control register in scratchpad */
+	str	r4, [r5, #0xC8]
+	ldr	r2, cache_pred_disable_mask
+	and	r4, r2
+	mcr	p15, 0, r4, c1, c0, 0
+
+	ldmfd	sp!, {r0-r12, pc}		@ restore regs and return
+save_context_wfi:
+	/*b	save_context_wfi*/	@ enable to debug save code
+	mov	r8, r0 /* Store SDRAM address in r8 */
+        /* Check what that target sleep state is:stored in r1*/
+        /* 1 - Only L1 and logic lost */
+        /* 2 - Only L2 lost */
+        /* 3 - Both L1 and L2 lost */
+	cmp	r1, #0x2 /* Only L2 lost */
+	beq	clean_l2
+	cmp	r1, #0x1 /* L2 retained */
+	/* r9 stores whether to clean L2 or not*/
+	moveq	r9, #0x0 /* Dont Clean L2 */
+	movne	r9, #0x1 /* Clean L2 */
+l1_logic_lost:
+	/* Store sp and spsr to SDRAM */
+	mov	r4, sp
+	mrs	r5, spsr
+	mov	r6, lr
+	stmia	r8!, {r4-r6}
+	/* Save all ARM registers */
+	/* Coprocessor access control register */
+	mrc	p15, 0, r6, c1, c0, 2
+	stmia	r8!, {r6}
+	/* TTBR0, TTBR1 and Translation table base control */
+	mrc	p15, 0, r4, c2, c0, 0
+	mrc	p15, 0, r5, c2, c0, 1
+	mrc	p15, 0, r6, c2, c0, 2
+	stmia	r8!, {r4-r6}
+	/* Domain access control register, data fault status register,
+	and instruction fault status register */
+	mrc	p15, 0, r4, c3, c0, 0
+	mrc	p15, 0, r5, c5, c0, 0
+	mrc	p15, 0, r6, c5, c0, 1
+	stmia	r8!, {r4-r6}
+	/* Data aux fault status register, instruction aux fault status,
+	datat fault address register and instruction fault address register*/
+	mrc	p15, 0, r4, c5, c1, 0
+	mrc	p15, 0, r5, c5, c1, 1
+	mrc	p15, 0, r6, c6, c0, 0
+	mrc	p15, 0, r7, c6, c0, 2
+	stmia	r8!, {r4-r7}
+	/* user r/w thread and process ID, user r/o thread and process ID,
+	priv only thread and process ID, cache size selection */
+	mrc	p15, 0, r4, c13, c0, 2
+	mrc	p15, 0, r5, c13, c0, 3
+	mrc	p15, 0, r6, c13, c0, 4
+	mrc	p15, 2, r7, c0, c0, 0
+	stmia	r8!, {r4-r7}
+	/* Data TLB lockdown, instruction TLB lockdown registers */
+	mrc	p15, 0, r5, c10, c0, 0
+	mrc	p15, 0, r6, c10, c0, 1
+	stmia	r8!, {r5-r6}
+	/* Secure or non secure vector base address, FCSE PID, Context PID*/
+	mrc	p15, 0, r4, c12, c0, 0
+	mrc	p15, 0, r5, c13, c0, 0
+	mrc	p15, 0, r6, c13, c0, 1
+	stmia	r8!, {r4-r6}
+	/* Primary remap, normal remap registers */
+	mrc	p15, 0, r4, c10, c2, 0
+	mrc	p15, 0, r5, c10, c2, 1
+	stmia	r8!,{r4-r5}
+	/* Store SP, LR, SPSR registers for SUP, FIQ, IRQ, ABORT and USER
+	modes into SDRAM */
+
+	/* move SDRAM address to r7 as r8 is banked in FIQ*/
+	mov	r7, r8
+
+	/* Save current mode */
+	mrs	r2, cpsr
+	/* FIQ mode */
+	bic	r0, r2, #0x1F
+	orr	r0, r0, #0x11
+	msr	cpsr, r0 /* go to FIQ mode */
+	stmia	r7!, {r8-r12}
+	mov	r4, r13 /* move SP into r4*/
+	mov	r5, r14
+	mrs	r6, spsr
+	stmia	r7!, {r4-r6}
+
+	/* IRQ mode */
+	bic	r0, r2, #0x1F
+	orr	r0, r0, #0x12
+	msr	cpsr, r0
+	mov	r4, r13
+	mov	r5, r14
+	mrs	r6, spsr
+	stmia	r7!, {r4-r6}
+
+	/* Abort mode */
+	bic	r0, r2, #0x1F
+	orr	r0, r0, #0x17
+	msr	cpsr, r0
+	mov	r4, r13
+	mov	r5, r14
+	mrs	r6, spsr
+	stmia	r7!, {r4-r6}
+
+	/* UNDEF mode */
+	bic	r0, r2, #0x1F
+	orr	r0, r0, #0x1B
+	msr	cpsr, r0
+	mov	r4, r13
+	mov	r5, r14
+	mrs	r6, spsr
+	stmia	r7!, {r4-r6}
+
+	/* System (USER mode) */
+	bic	r0, r2, #0x1F
+	orr	r0, r0, #0x1F
+	msr	cpsr, r0
+	mov	r4, r13
+	mov	r5, r14
+	mrs	r6, spsr
+	stmia	r7!, {r4-r6}
+
+	/* Back to original mode */
+	msr	cpsr, r2
+
+	/* Store current cpsr*/
+	stmia	r7!, {r2}
+
+	mrc	p15, 0, r4, c1, c0, 0
+	/* save control register */
+	stmia	r7!, {r4}
+clean_caches:
+	/* Clean Data or unified cache to POU*/
+	/* How to invalidate only L1 cache???? - #FIX_ME# */
+	/* mcr	p15, 0, r11, c7, c11, 1 */
+	cmp	r9, #1 /* Check whether L2 inval is required or not*/
+	bne	skip_l2_inval
+clean_l2:
+	/* read clidr */
+	mrc     p15, 1, r0, c0, c0, 1
+	/* extract loc from clidr */
+	ands    r3, r0, #0x7000000
+	/* left align loc bit field */
+	mov     r3, r3, lsr #23
+	/* if loc is 0, then no need to clean */
+	beq     finished
+	/* start clean at cache level 0 */
+	mov     r10, #0
+loop1:
+	/* work out 3x current cache level */
+	add     r2, r10, r10, lsr #1
+	/* extract cache type bits from clidr*/
+	mov     r1, r0, lsr r2
+	/* mask of the bits for current cache only */
+	and     r1, r1, #7
+	/* see what cache we have at this level */
+	cmp     r1, #2
+	/* skip if no cache, or just i-cache */
+	blt     skip
+	/* select current cache level in cssr */
+	mcr     p15, 2, r10, c0, c0, 0
+	/* isb to sych the new cssr&csidr */
+	isb
+	/* read the new csidr */
+	mrc     p15, 1, r1, c0, c0, 0
+	/* extract the length of the cache lines */
+	and     r2, r1, #7
+	/* add 4 (line length offset) */
+	add     r2, r2, #4
+	ldr     r4, assoc_mask
+	/* find maximum number on the way size */
+	ands    r4, r4, r1, lsr #3
+	/* find bit position of way size increment */
+	clz     r5, r4
+	ldr     r7, numset_mask
+	/* extract max number of the index size*/
+	ands    r7, r7, r1, lsr #13
+loop2:
+	mov     r9, r4
+	/* create working copy of max way size*/
+loop3:
+	/* factor way and cache number into r11 */
+	orr     r11, r10, r9, lsl r5
+	/* factor index number into r11 */
+	orr     r11, r11, r7, lsl r2
+	/*clean & invalidate by set/way */
+	mcr     p15, 0, r11, c7, c10, 2
+	/* decrement the way*/
+	subs    r9, r9, #1
+	bge     loop3
+	/*decrement the index */
+	subs    r7, r7, #1
+	bge     loop2
+skip:
+	add     r10, r10, #2
+	/* increment cache number */
+	cmp     r3, r10
+	bgt     loop1
+finished:
+	/*swith back to cache level 0 */
+	mov     r10, #0
+	/* select current cache level in cssr */
+	mcr     p15, 2, r10, c0, c0, 0
+	isb
+skip_l2_inval:
+	/* Data memory barrier and Data sync barrier */
+	mov     r1, #0
+	mcr     p15, 0, r1, c7, c10, 4
+	mcr     p15, 0, r1, c7, c10, 5
+
+	wfi                             @ wait for interrupt
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	bl i_dll_wait
+	/* restore regs and return */
+	ldmfd   sp!, {r0-r12, pc}
+
+i_dll_wait:
+	ldr     r4, clk_stabilize_delay
+
+i_dll_delay:
+	subs    r4, r4, #0x1
+	bne     i_dll_delay
+	ldr     r4, sdrc_power
+	ldr     r5, [r4]
+	bic     r5, r5, #0x40
+	str     r5, [r4]
+	bx	lr
+pm_prepwstst_core:
+	.word	PM_PREPWSTST_CORE_V
+pm_prepwstst_mpu:
+	.word	PM_PREPWSTST_MPU_V
+pm_pwstctrl_mpu:
+	.word	PM_PWSTCTRL_MPU_P
+scratchpad_base:
+	.word	SCRATCHPAD_BASE_P
+sdrc_power:
+	.word SDRC_POWER_V
+context_mem:
+	.word	0x803E3E14
+clk_stabilize_delay:
+	.word 0x000001FF
+assoc_mask:
+	.word	0x3ff
+numset_mask:
+	.word	0x7fff
+ttbrbit_mask:
+	.word	0xFFFFC000
+table_index_mask:
+	.word	0xFFF00000
+table_entry:
+	.word	0x00000C02
+cache_pred_disable_mask:
+	.word	0xFFFFE7FB
+ENTRY(omap34xx_cpu_suspend_sz)
+	.word	. - omap34xx_cpu_suspend
diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c
index 34a56a1..215d463 100644
--- a/arch/arm/mach-omap2/usb-musb.c
+++ b/arch/arm/mach-omap2/usb-musb.c
@@ -28,7 +28,6 @@
 
 #include <mach/hardware.h>
 #include <mach/irqs.h>
-#include <mach/pm.h>
 #include <mach/mux.h>
 #include <mach/usb.h>
 
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 9dd68fa..4bc9ed7 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -171,7 +171,7 @@ endchoice
 
 config OMAP_SERIAL_WAKE
 	bool "Enable wake-up events for serial ports"
-	depends on OMAP_MUX
+	depends on ARCH_OMAP1 && OMAP_MUX
 	default y
 	help
 	  Select this option if you want to have your system wake up
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c
index e1add78..ec218a3 100644
--- a/arch/arm/plat-omap/common.c
+++ b/arch/arm/plat-omap/common.c
@@ -11,7 +11,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/pm.h>
 #include <linux/console.h>
 #include <linux/serial.h>
 #include <linux/tty.h>
diff --git a/arch/arm/plat-omap/include/mach/pm.h b/arch/arm/plat-omap/include/mach/pm.h
deleted file mode 100644
index ce6ee79..0000000
--- a/arch/arm/plat-omap/include/mach/pm.h
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * arch/arm/plat-omap/include/mach/pm.h
- *
- * Header file for OMAP Power Management Routines
- *
- * Author: MontaVista Software, Inc.
- *	   support@mvista.com
- *
- * Copyright 2002 MontaVista Software Inc.
- *
- * Cleanup 2004 for Linux 2.6 by Dirk Behme <dirk.behme@de.bosch.com>
- *
- * 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; either version 2 of the License, or (at your
- * option) any later version.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __ASM_ARCH_OMAP_PM_H
-#define __ASM_ARCH_OMAP_PM_H
-
-/*
- * ----------------------------------------------------------------------------
- * Register and offset definitions to be used in PM assembler code
- * ----------------------------------------------------------------------------
- */
-#define CLKGEN_REG_ASM_BASE		IO_ADDRESS(0xfffece00)
-#define ARM_IDLECT1_ASM_OFFSET		0x04
-#define ARM_IDLECT2_ASM_OFFSET		0x08
-
-#define TCMIF_ASM_BASE			IO_ADDRESS(0xfffecc00)
-#define EMIFS_CONFIG_ASM_OFFSET		0x0c
-#define EMIFF_SDRAM_CONFIG_ASM_OFFSET	0x20
-
-/*
- * ----------------------------------------------------------------------------
- * Power management bitmasks
- * ----------------------------------------------------------------------------
- */
-#define IDLE_WAIT_CYCLES		0x00000fff
-#define PERIPHERAL_ENABLE		0x2
-
-#define SELF_REFRESH_MODE		0x0c000001
-#define IDLE_EMIFS_REQUEST		0xc
-#define MODEM_32K_EN			0x1
-#define PER_EN				0x1
-
-#define CPU_SUSPEND_SIZE		200
-#define ULPD_LOW_PWR_EN			0x0001
-#define ULPD_DEEP_SLEEP_TRANSITION_EN	0x0010
-#define ULPD_SETUP_ANALOG_CELL_3_VAL	0
-#define ULPD_POWER_CTRL_REG_VAL		0x0219
-
-#define DSP_IDLE_DELAY			10
-#define DSP_IDLE			0x0040
-#define DSP_RST				0x0004
-#define DSP_ENABLE			0x0002
-#define SUFFICIENT_DSP_RESET_TIME	1000
-#define DEFAULT_MPUI_CONFIG		0x05cf
-#define ENABLE_XORCLK			0x2
-#define DSP_CLOCK_ENABLE		0x2000
-#define DSP_IDLE_MODE			0x2
-#define TC_IDLE_REQUEST			(0x0000000c)
-
-#define IRQ_LEVEL2			(1<<0)
-#define IRQ_KEYBOARD			(1<<1)
-#define IRQ_UART2			(1<<15)
-
-#define PDE_BIT				0x08
-#define PWD_EN_BIT			0x04
-#define EN_PERCK_BIT			0x04
-
-#define OMAP1510_DEEP_SLEEP_REQUEST	0x0ec7
-#define OMAP1510_BIG_SLEEP_REQUEST	0x0cc5
-#define OMAP1510_IDLE_LOOP_REQUEST	0x0c00
-#define OMAP1510_IDLE_CLOCK_DOMAINS	0x2
-
-/* Both big sleep and deep sleep use same values. Difference is in ULPD. */
-#define OMAP1610_IDLECT1_SLEEP_VAL	0x13c7
-#define OMAP1610_IDLECT2_SLEEP_VAL	0x09c7
-#define OMAP1610_IDLECT3_VAL		0x3f
-#define OMAP1610_IDLECT3_SLEEP_ORMASK	0x2c
-#define OMAP1610_IDLECT3		0xfffece24
-#define OMAP1610_IDLE_LOOP_REQUEST	0x0400
-
-#define OMAP730_IDLECT1_SLEEP_VAL	0x16c7
-#define OMAP730_IDLECT2_SLEEP_VAL	0x09c7
-#define OMAP730_IDLECT3_VAL		0x3f
-#define OMAP730_IDLECT3		0xfffece24
-#define OMAP730_IDLE_LOOP_REQUEST	0x0C00
-
-#if     !defined(CONFIG_ARCH_OMAP730) && \
-	!defined(CONFIG_ARCH_OMAP15XX) && \
-	!defined(CONFIG_ARCH_OMAP16XX) && \
-	!defined(CONFIG_ARCH_OMAP24XX)
-#warning "Power management for this processor not implemented yet"
-#endif
-
-#ifndef __ASSEMBLER__
-
-#include <linux/clk.h>
-
-extern void prevent_idle_sleep(void);
-extern void allow_idle_sleep(void);
-
-extern void omap_pm_idle(void);
-extern void omap_pm_suspend(void);
-extern void omap730_cpu_suspend(unsigned short, unsigned short);
-extern void omap1510_cpu_suspend(unsigned short, unsigned short);
-extern void omap1610_cpu_suspend(unsigned short, unsigned short);
-extern void omap24xx_cpu_suspend(u32 dll_ctrl, void __iomem *sdrc_dlla_ctrl,
-					void __iomem *sdrc_power);
-extern void omap730_idle_loop_suspend(void);
-extern void omap1510_idle_loop_suspend(void);
-extern void omap1610_idle_loop_suspend(void);
-extern void omap24xx_idle_loop_suspend(void);
-
-extern unsigned int omap730_cpu_suspend_sz;
-extern unsigned int omap1510_cpu_suspend_sz;
-extern unsigned int omap1610_cpu_suspend_sz;
-extern unsigned int omap24xx_cpu_suspend_sz;
-extern unsigned int omap730_idle_loop_suspend_sz;
-extern unsigned int omap1510_idle_loop_suspend_sz;
-extern unsigned int omap1610_idle_loop_suspend_sz;
-extern unsigned int omap24xx_idle_loop_suspend_sz;
-
-#ifdef CONFIG_OMAP_SERIAL_WAKE
-extern void omap_serial_wake_trigger(int enable);
-#else
-#define omap_serial_wakeup_init()	{}
-#define omap_serial_wake_trigger(x)	{}
-#endif	/* CONFIG_OMAP_SERIAL_WAKE */
-
-#define ARM_SAVE(x) arm_sleep_save[ARM_SLEEP_SAVE_##x] = omap_readl(x)
-#define ARM_RESTORE(x) omap_writel((arm_sleep_save[ARM_SLEEP_SAVE_##x]), (x))
-#define ARM_SHOW(x) arm_sleep_save[ARM_SLEEP_SAVE_##x]
-
-#define DSP_SAVE(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x] = __raw_readw(x)
-#define DSP_RESTORE(x) __raw_writew((dsp_sleep_save[DSP_SLEEP_SAVE_##x]), (x))
-#define DSP_SHOW(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x]
-
-#define ULPD_SAVE(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x] = omap_readw(x)
-#define ULPD_RESTORE(x) omap_writew((ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]), (x))
-#define ULPD_SHOW(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]
-
-#define MPUI730_SAVE(x) mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x] = omap_readl(x)
-#define MPUI730_RESTORE(x) omap_writel((mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x]), (x))
-#define MPUI730_SHOW(x) mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x]
-
-#define MPUI1510_SAVE(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x] = omap_readl(x)
-#define MPUI1510_RESTORE(x) omap_writel((mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x]), (x))
-#define MPUI1510_SHOW(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x]
-
-#define MPUI1610_SAVE(x) mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x] = omap_readl(x)
-#define MPUI1610_RESTORE(x) omap_writel((mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]), (x))
-#define MPUI1610_SHOW(x) mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]
-
-#define OMAP24XX_SAVE(x) omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x] = x
-#define OMAP24XX_RESTORE(x) x = omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x]
-#define OMAP24XX_SHOW(x) omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x]
-
-/*
- * List of global OMAP registers to preserve.
- * More ones like CP and general purpose register values are preserved
- * with the stack pointer in sleep.S.
- */
-
-enum arm_save_state {
-	ARM_SLEEP_SAVE_START = 0,
-	/*
-	 * MPU control registers 32 bits
-	 */
-	ARM_SLEEP_SAVE_ARM_CKCTL,
-	ARM_SLEEP_SAVE_ARM_IDLECT1,
-	ARM_SLEEP_SAVE_ARM_IDLECT2,
-	ARM_SLEEP_SAVE_ARM_IDLECT3,
-	ARM_SLEEP_SAVE_ARM_EWUPCT,
-	ARM_SLEEP_SAVE_ARM_RSTCT1,
-	ARM_SLEEP_SAVE_ARM_RSTCT2,
-	ARM_SLEEP_SAVE_ARM_SYSST,
-	ARM_SLEEP_SAVE_SIZE
-};
-
-enum dsp_save_state {
-	DSP_SLEEP_SAVE_START = 0,
-	/*
-	 * DSP registers 16 bits
-	 */
-	DSP_SLEEP_SAVE_DSP_IDLECT2,
-	DSP_SLEEP_SAVE_SIZE
-};
-
-enum ulpd_save_state {
-	ULPD_SLEEP_SAVE_START = 0,
-	/*
-	 * ULPD registers 16 bits
-	 */
-	ULPD_SLEEP_SAVE_ULPD_IT_STATUS,
-	ULPD_SLEEP_SAVE_ULPD_CLOCK_CTRL,
-	ULPD_SLEEP_SAVE_ULPD_SOFT_REQ,
-	ULPD_SLEEP_SAVE_ULPD_STATUS_REQ,
-	ULPD_SLEEP_SAVE_ULPD_DPLL_CTRL,
-	ULPD_SLEEP_SAVE_ULPD_POWER_CTRL,
-	ULPD_SLEEP_SAVE_SIZE
-};
-
-enum mpui1510_save_state {
-	MPUI1510_SLEEP_SAVE_START = 0,
-	/*
-	 * MPUI registers 32 bits
-	 */
-	MPUI1510_SLEEP_SAVE_MPUI_CTRL,
-	MPUI1510_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
-	MPUI1510_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
-	MPUI1510_SLEEP_SAVE_MPUI_DSP_STATUS,
-	MPUI1510_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
-	MPUI1510_SLEEP_SAVE_EMIFS_CONFIG,
-	MPUI1510_SLEEP_SAVE_OMAP_IH1_MIR,
-	MPUI1510_SLEEP_SAVE_OMAP_IH2_MIR,
-#if defined(CONFIG_ARCH_OMAP15XX)
-	MPUI1510_SLEEP_SAVE_SIZE
-#else
-	MPUI1510_SLEEP_SAVE_SIZE = 0
-#endif
-};
-
-enum mpui730_save_state {
-	MPUI730_SLEEP_SAVE_START = 0,
-	/*
-	 * MPUI registers 32 bits
-	 */
-	MPUI730_SLEEP_SAVE_MPUI_CTRL,
-	MPUI730_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
-	MPUI730_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
-	MPUI730_SLEEP_SAVE_MPUI_DSP_STATUS,
-	MPUI730_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
-	MPUI730_SLEEP_SAVE_EMIFS_CONFIG,
-	MPUI730_SLEEP_SAVE_OMAP_IH1_MIR,
-	MPUI730_SLEEP_SAVE_OMAP_IH2_0_MIR,
-	MPUI730_SLEEP_SAVE_OMAP_IH2_1_MIR,
-#if defined(CONFIG_ARCH_OMAP730)
-	MPUI730_SLEEP_SAVE_SIZE
-#else
-	MPUI730_SLEEP_SAVE_SIZE = 0
-#endif
-};
-
-enum mpui1610_save_state {
-	MPUI1610_SLEEP_SAVE_START = 0,
-	/*
-	 * MPUI registers 32 bits
-	 */
-	MPUI1610_SLEEP_SAVE_MPUI_CTRL,
-	MPUI1610_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
-	MPUI1610_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
-	MPUI1610_SLEEP_SAVE_MPUI_DSP_STATUS,
-	MPUI1610_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
-	MPUI1610_SLEEP_SAVE_EMIFS_CONFIG,
-	MPUI1610_SLEEP_SAVE_OMAP_IH1_MIR,
-	MPUI1610_SLEEP_SAVE_OMAP_IH2_0_MIR,
-	MPUI1610_SLEEP_SAVE_OMAP_IH2_1_MIR,
-	MPUI1610_SLEEP_SAVE_OMAP_IH2_2_MIR,
-	MPUI1610_SLEEP_SAVE_OMAP_IH2_3_MIR,
-#if defined(CONFIG_ARCH_OMAP16XX)
-	MPUI1610_SLEEP_SAVE_SIZE
-#else
-	MPUI1610_SLEEP_SAVE_SIZE = 0
-#endif
-};
-
-enum omap24xx_save_state {
-	OMAP24XX_SLEEP_SAVE_START = 0,
-	OMAP24XX_SLEEP_SAVE_INTC_MIR0,
-	OMAP24XX_SLEEP_SAVE_INTC_MIR1,
-	OMAP24XX_SLEEP_SAVE_INTC_MIR2,
-
-	OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_MPU,
-	OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_GFX,
-	OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_DSP,
-	OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_MDM,
-
-	OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_MPU,
-	OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_CORE,
-	OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_GFX,
-	OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_DSP,
-	OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_MDM,
-
-	OMAP24XX_SLEEP_SAVE_CM_IDLEST1_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_IDLEST2_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_IDLEST3_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_IDLEST4_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_IDLEST_GFX,
-	OMAP24XX_SLEEP_SAVE_CM_IDLEST_WKUP,
-	OMAP24XX_SLEEP_SAVE_CM_IDLEST_CKGEN,
-	OMAP24XX_SLEEP_SAVE_CM_IDLEST_DSP,
-	OMAP24XX_SLEEP_SAVE_CM_IDLEST_MDM,
-
-	OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE1_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE2_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE3_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE4_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_WKUP,
-	OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_PLL,
-	OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_DSP,
-	OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_MDM,
-
-	OMAP24XX_SLEEP_SAVE_CM_FCLKEN1_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_FCLKEN2_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_ICLKEN1_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_ICLKEN2_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_ICLKEN3_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_ICLKEN4_CORE,
-	OMAP24XX_SLEEP_SAVE_GPIO1_IRQENABLE1,
-	OMAP24XX_SLEEP_SAVE_GPIO2_IRQENABLE1,
-	OMAP24XX_SLEEP_SAVE_GPIO3_IRQENABLE1,
-	OMAP24XX_SLEEP_SAVE_GPIO4_IRQENABLE1,
-	OMAP24XX_SLEEP_SAVE_GPIO3_OE,
-	OMAP24XX_SLEEP_SAVE_GPIO4_OE,
-	OMAP24XX_SLEEP_SAVE_GPIO3_RISINGDETECT,
-	OMAP24XX_SLEEP_SAVE_GPIO3_FALLINGDETECT,
-	OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SPI1_NCS2,
-	OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_MCBSP1_DX,
-	OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SSI1_FLAG_TX,
-	OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SYS_NIRQW0,
-	OMAP24XX_SLEEP_SAVE_SIZE
-};
-
-#endif /* ASSEMBLER */
-#endif /* __ASM_ARCH_OMAP_PM_H */
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index f2e9de1..6391e3d 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -39,7 +39,6 @@
 #include <mach/gpmc.h>
 #include <mach/onenand.h>
 #include <mach/gpio.h>
-#include <mach/pm.h>
 
 #include <mach/dma.h>
 
-- 
1.6.2.2


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

* [PATCH 02/11] OMAP: Add new function to check wether there is irq pending
  2009-05-15 18:40 ` [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap Kevin Hilman
@ 2009-05-15 18:40   ` Kevin Hilman
  2009-05-15 18:40     ` [PATCH 03/11] OMAP3: PM: Force IVA2 into idle during bootup Kevin Hilman
  2009-05-18 13:32   ` [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap Russell King - ARM Linux
  1 sibling, 1 reply; 31+ messages in thread
From: Kevin Hilman @ 2009-05-15 18:40 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: linux-omap, Jouni Hogander, Tony Lindgren, Kevin Hilman

From: Jouni Hogander <jouni.hogander@nokia.com>

Add common omap2/3 function to check wether there is irq pending.
Switch to use it in omap2 pm code instead of its own.

Signed-off-by: Jouni Hogander <jouni.hogander@nokia.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
 arch/arm/mach-omap2/irq.c              |   17 ++++++++++++++++-
 arch/arm/mach-omap2/pm24xx.c           |   19 +++----------------
 arch/arm/plat-omap/include/mach/irqs.h |    1 +
 3 files changed, 20 insertions(+), 17 deletions(-)

diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index 998c5c4..f5de43d 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -28,7 +28,6 @@
 #define INTC_MIR_CLEAR0		0x0088
 #define INTC_MIR_SET0		0x008c
 #define INTC_PENDING_IRQ0	0x0098
-
 /* Number of IRQ state bits in each MIR register */
 #define IRQ_BITS_PER_REG	32
 
@@ -157,6 +156,22 @@ static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
 	intc_bank_write_reg(1 << 0, bank, INTC_SYSCONFIG);
 }
 
+int omap_irq_pending(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
+		struct omap_irq_bank *bank = irq_banks + i;
+		int irq;
+
+		for (irq = 0; irq < bank->nr_irqs; irq += 32)
+			if (intc_bank_read_reg(bank, INTC_PENDING_IRQ0 +
+					       ((irq >> 5) << 5)))
+				return 1;
+	}
+	return 0;
+}
+
 void __init omap_init_irq(void)
 {
 	unsigned long nr_of_irqs = 0;
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index 2a2d1a3..da4294d 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -77,19 +77,6 @@ static int omap2_fclks_active(void)
 	return 0;
 }
 
-static int omap2_irq_pending(void)
-{
-	u32 pending_reg = 0x480fe098;
-	int i;
-
-	for (i = 0; i < 4; i++) {
-		if (omap_readl(pending_reg))
-			return 1;
-		pending_reg += 0x20;
-	}
-	return 0;
-}
-
 static void omap2_enter_full_retention(void)
 {
 	u32 l;
@@ -128,7 +115,7 @@ static void omap2_enter_full_retention(void)
 
 	/* One last check for pending IRQs to avoid extra latency due
 	 * to sleeping unnecessarily. */
-	if (omap2_irq_pending())
+	if (omap_irq_pending())
 		goto no_sleep;
 
 	/* Jump to SRAM suspend code */
@@ -274,13 +261,13 @@ static void omap2_pm_idle(void)
 	local_fiq_disable();
 
 	if (!omap2_can_sleep()) {
-		if (!atomic_read(&sleep_block) && omap2_irq_pending())
+		if (!atomic_read(&sleep_block) && omap_irq_pending())
 			goto out;
 		omap2_enter_mpu_retention();
 		goto out;
 	}
 
-	if (omap2_irq_pending())
+	if (omap_irq_pending())
 		goto out;
 
 	omap2_enter_full_retention();
diff --git a/arch/arm/plat-omap/include/mach/irqs.h b/arch/arm/plat-omap/include/mach/irqs.h
index 7f57ee6..f5f7c92 100644
--- a/arch/arm/plat-omap/include/mach/irqs.h
+++ b/arch/arm/plat-omap/include/mach/irqs.h
@@ -467,6 +467,7 @@
 
 #ifndef __ASSEMBLY__
 extern void omap_init_irq(void);
+extern int omap_irq_pending(void);
 #endif
 
 #include <mach/hardware.h>
-- 
1.6.2.2


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

* [PATCH 03/11] OMAP3: PM: Force IVA2 into idle during bootup
  2009-05-15 18:40   ` [PATCH 02/11] OMAP: Add new function to check wether there is irq pending Kevin Hilman
@ 2009-05-15 18:40     ` Kevin Hilman
  2009-05-15 18:40       ` [PATCH 04/11] OMAP3: PM: Add wake-up bit defintiions for CONTROL_PADCONF_X Kevin Hilman
  0 siblings, 1 reply; 31+ messages in thread
From: Kevin Hilman @ 2009-05-15 18:40 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: linux-omap, Kevin Hilman

Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
 arch/arm/mach-omap2/pm34xx.c              |   50 +++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/mach/control.h |    5 +++
 2 files changed, 55 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 0fb6bec..1a13362 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -358,6 +358,54 @@ static struct platform_suspend_ops omap_pm_ops = {
 	.valid		= suspend_valid_only_mem,
 };
 
+
+/**
+ * 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 */
+	cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
+
+	/* if no clock activity, nothing else to do */
+	if (!(cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSTST) &
+	      OMAP3430_CLKACTIVITY_IVA2_MASK))
+		return;
+
+	/* Reset IVA2 */
+	prm_write_mod_reg(OMAP3430_RST1_IVA2 |
+			  OMAP3430_RST2_IVA2 |
+			  OMAP3430_RST3_IVA2,
+			  OMAP3430_IVA2_MOD, RM_RSTCTRL);
+
+	/* Enable IVA2 clock */
+	cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2,
+			 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 */
+	prm_write_mod_reg(0, OMAP3430_IVA2_MOD, RM_RSTCTRL);
+
+	/* Disable IVA2 clock */
+	cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
+
+	/* Reset IVA2 */
+	prm_write_mod_reg(OMAP3430_RST1_IVA2 |
+			  OMAP3430_RST2_IVA2 |
+			  OMAP3430_RST3_IVA2,
+			  OMAP3430_IVA2_MOD, RM_RSTCTRL);
+}
+
 static void __init prcm_setup_regs(void)
 {
 	/* reset modem */
@@ -517,6 +565,8 @@ static void __init prcm_setup_regs(void)
 	 * it is selected to mpu wakeup goup */
 	prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
 			  OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
+
+	omap3_iva_idle();
 }
 
 static int __init pwrdms_setup(struct powerdomain *pwrdm)
diff --git a/arch/arm/plat-omap/include/mach/control.h b/arch/arm/plat-omap/include/mach/control.h
index 269147f..d38697b 100644
--- a/arch/arm/plat-omap/include/mach/control.h
+++ b/arch/arm/plat-omap/include/mach/control.h
@@ -189,6 +189,11 @@
 #define OMAP2_PBIASLITEPWRDNZ0		(1 << 1)
 #define OMAP2_PBIASLITEVMODE0		(1 << 0)
 
+/* CONTROL_IVA2_BOOTMOD bits */
+#define OMAP3_IVA2_BOOTMOD_SHIFT	0
+#define OMAP3_IVA2_BOOTMOD_MASK		(0xf << 0)
+#define OMAP3_IVA2_BOOTMOD_IDLE		(0x1 << 0)
+
 #ifndef __ASSEMBLY__
 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
 extern void __iomem *omap_ctrl_base_get(void);
-- 
1.6.2.2


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

* [PATCH 04/11] OMAP3: PM: Add wake-up bit defintiions for CONTROL_PADCONF_X
  2009-05-15 18:40     ` [PATCH 03/11] OMAP3: PM: Force IVA2 into idle during bootup Kevin Hilman
@ 2009-05-15 18:40       ` Kevin Hilman
  2009-05-15 18:40         ` [PATCH 05/11] OMAP3: PM: UART: disable clocks when idle and off-mode support Kevin Hilman
  0 siblings, 1 reply; 31+ messages in thread
From: Kevin Hilman @ 2009-05-15 18:40 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: linux-omap, Kevin Hilman

Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
 arch/arm/plat-omap/include/mach/control.h |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/arch/arm/plat-omap/include/mach/control.h b/arch/arm/plat-omap/include/mach/control.h
index d38697b..a9f05e5 100644
--- a/arch/arm/plat-omap/include/mach/control.h
+++ b/arch/arm/plat-omap/include/mach/control.h
@@ -194,6 +194,10 @@
 #define OMAP3_IVA2_BOOTMOD_MASK		(0xf << 0)
 #define OMAP3_IVA2_BOOTMOD_IDLE		(0x1 << 0)
 
+/* CONTROL_PADCONF_X bits */
+#define OMAP3_PADCONF_WAKEUPEVENT0	(1 << 15)
+#define OMAP3_PADCONF_WAKEUPENABLE0	(1 << 14)
+
 #ifndef __ASSEMBLY__
 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
 extern void __iomem *omap_ctrl_base_get(void);
-- 
1.6.2.2


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

* [PATCH 05/11] OMAP3: PM: UART: disable clocks when idle and off-mode support
  2009-05-15 18:40       ` [PATCH 04/11] OMAP3: PM: Add wake-up bit defintiions for CONTROL_PADCONF_X Kevin Hilman
@ 2009-05-15 18:40         ` Kevin Hilman
  2009-05-15 18:40           ` [PATCH 06/11] OMAP3: PM: Add D2D clocks and auto-idle setup to PRCM init Kevin Hilman
  0 siblings, 1 reply; 31+ messages in thread
From: Kevin Hilman @ 2009-05-15 18:40 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: linux-omap, Kevin Hilman, Tero Kristo, Jouni Hogander

This patch allows the UART clocks to be disabled when the OMAP UARTs
are inactive, thus permitting the chip to hit retention in idle.
After the timeout of an activity timer, each UART is allowed to
disable its clocks so the system can enter retention.  The activity
timer is (re)activated on any UART interrupt, UART wake event or any
IO pad wakeup.  The actual disable of the UART clocks is done in the
'prepare_idle' hook called from the OMAP idle loop.

While the activity timer is active, the smart-idle mode of the UART is
also disabled.  This is due to a "feature" of the UART module that
after a UART wakeup, the smart-idle mode may be entered before the
UART has communicated the interrupt, or upon TX, an idle mode may be
entered before the TX FIFOs are emptied.

Upon suspend, the 'prepare_suspend' hook cancels any pending activity
timers and allows the clocks to be disabled.

To enable the clock-disabling feature of this patch, do

  # echo 1 > /sys/power/clocks_off_while_idle

In addition, upon disabling clocks the UART state is saved in case
of an off-mode transition while clocks are off.

Special thanks to Tero Kristo for the initial ideas and first versions
of UART idle support, and to Jouni Hogander for extra testing and
bugfixes.

Tested on OMAP3 (Beagle, custom HW) and OMAP2 (n810)

Cc: Tero Kristo <tero.kristo@nokia.com>
Cc: Jouni Hogander <jouni.hogander@nokia.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
 arch/arm/mach-omap2/pm24xx.c             |   16 ++-
 arch/arm/mach-omap2/pm34xx.c             |   15 ++
 arch/arm/mach-omap2/serial.c             |  391 ++++++++++++++++++++++++++++--
 arch/arm/plat-omap/include/mach/common.h |    2 -
 arch/arm/plat-omap/include/mach/serial.h |    9 +
 5 files changed, 406 insertions(+), 27 deletions(-)

diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index da4294d..026cc30 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -72,6 +72,11 @@ static int omap2_fclks_active(void)
 
 	f1 = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
 	f2 = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+
+	/* Ignore UART clocks.  These are handled by UART core (serial.c) */
+	f1 &= ~(OMAP24XX_EN_UART1 | OMAP24XX_EN_UART2);
+	f2 &= ~OMAP24XX_EN_UART3;
+
 	if (f1 | f2)
 		return 1;
 	return 0;
@@ -118,12 +123,20 @@ static void omap2_enter_full_retention(void)
 	if (omap_irq_pending())
 		goto no_sleep;
 
+	omap_uart_prepare_idle(0);
+	omap_uart_prepare_idle(1);
+	omap_uart_prepare_idle(2);
+
 	/* Jump to SRAM suspend code */
 	omap2_sram_suspend(sdrc_read_reg(SDRC_DLLA_CTRL),
 			   OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL),
 			   OMAP_SDRC_REGADDR(SDRC_POWER));
-no_sleep:
 
+	omap_uart_resume_idle(2);
+	omap_uart_resume_idle(1);
+	omap_uart_resume_idle(0);
+
+no_sleep:
 	if (omap2_pm_debug) {
 		unsigned long long tmp;
 
@@ -297,6 +310,7 @@ static int omap2_pm_suspend(void)
 	mir1 = omap_readl(0x480fe0a4);
 	omap_writel(1 << 5, 0x480fe0ac);
 
+	omap_uart_prepare_suspend();
 	omap2_enter_full_retention();
 
 	omap_writel(mir1, 0x480fe0a4);
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 1a13362..24a146c 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -27,6 +27,7 @@
 #include <mach/clockdomain.h>
 #include <mach/powerdomain.h>
 #include <mach/control.h>
+#include <mach/serial.h>
 
 #include "cm.h"
 #include "cm-regbits-34xx.h"
@@ -170,9 +171,15 @@ static void omap_sram_idle(void)
 		return;
 	}
 	omap2_gpio_prepare_for_retention();
+	omap_uart_prepare_idle(0);
+	omap_uart_prepare_idle(1);
+	omap_uart_prepare_idle(2);
 
 	_omap_sram_idle(NULL, save_state);
 
+	omap_uart_resume_idle(2);
+	omap_uart_resume_idle(1);
+	omap_uart_resume_idle(0);
 	omap2_gpio_resume_after_retention();
 }
 
@@ -205,6 +212,11 @@ static int omap3_fclks_active(void)
 				  CM_FCLKEN);
 	fck_per = cm_read_mod_reg(OMAP3430_PER_MOD,
 				  CM_FCLKEN);
+
+	/* Ignore UART clocks.  These are handled by UART core (serial.c) */
+	fck_core1 &= ~(OMAP3430_EN_UART1 | OMAP3430_EN_UART2);
+	fck_per &= ~OMAP3430_EN_UART3;
+
 	if (fck_core1 | fck_core3 | fck_sgx | fck_dss |
 	    fck_cam | fck_per | fck_usbhost)
 		return 1;
@@ -215,6 +227,8 @@ static int omap3_can_sleep(void)
 {
 	if (!enable_dyn_sleep)
 		return 0;
+	if (!omap_uart_can_sleep())
+		return 0;
 	if (omap3_fclks_active())
 		return 0;
 	if (atomic_read(&sleep_block) > 0)
@@ -307,6 +321,7 @@ static int omap3_pm_suspend(void)
 			goto restore;
 	}
 
+	omap_uart_prepare_suspend();
 	omap_sram_idle();
 
 restore:
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 4dcf39c..cb191d0 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -6,6 +6,8 @@
  * Copyright (C) 2005-2008 Nokia Corporation
  * Author: Paul Mundt <paul.mundt@nokia.com>
  *
+ * Major rework for PM support by Kevin Hilman
+ *
  * Based off of arch/arm/mach-omap/omap1/serial.c
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -21,9 +23,48 @@
 
 #include <mach/common.h>
 #include <mach/board.h>
+#include <mach/clock.h>
+#include <mach/control.h>
+
+#include "prm.h"
+#include "pm.h"
+#include "prm-regbits-34xx.h"
+
+#define DEFAULT_TIMEOUT (2 * HZ)
+
+struct omap_uart_state {
+	int num;
+	int can_sleep;
+	struct timer_list timer;
+	u32 timeout;
 
-static struct clk *uart_ick[OMAP_MAX_NR_PORTS];
-static struct clk *uart_fck[OMAP_MAX_NR_PORTS];
+	void __iomem *wk_st;
+	void __iomem *wk_en;
+	u32 wk_mask;
+	u32 padconf;
+
+	struct clk *ick;
+	struct clk *fck;
+	int clocked;
+
+	struct plat_serial8250_port *p;
+	struct list_head node;
+
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
+	int context_valid;
+
+	/* Registers to be saved/restored for OFF-mode */
+	u16 dll;
+	u16 dlh;
+	u16 ier;
+	u16 sysc;
+	u16 scr;
+	u16 wer;
+#endif
+};
+
+static struct omap_uart_state omap_uart[OMAP_MAX_NR_PORTS];
+static LIST_HEAD(uart_list);
 
 static struct plat_serial8250_port serial_platform_data[] = {
 	{
@@ -74,30 +115,323 @@ static inline void serial_write_reg(struct plat_serial8250_port *p, int offset,
  * properly. Note that the TX watermark initialization may not be needed
  * once the 8250.c watermark handling code is merged.
  */
-static inline void __init omap_serial_reset(struct plat_serial8250_port *p)
+static inline void __init omap_uart_reset(struct omap_uart_state *uart)
 {
+	struct plat_serial8250_port *p = uart->p;
+
 	serial_write_reg(p, UART_OMAP_MDR1, 0x07);
 	serial_write_reg(p, UART_OMAP_SCR, 0x08);
 	serial_write_reg(p, UART_OMAP_MDR1, 0x00);
 	serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0));
 }
 
-void omap_serial_enable_clocks(int enable)
+#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3)
+
+static int enable_off_mode; /* to be removed by full off-mode patches */
+
+static void omap_uart_save_context(struct omap_uart_state *uart)
 {
-	int i;
-	for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
-		if (uart_ick[i] && uart_fck[i]) {
-			if (enable) {
-				clk_enable(uart_ick[i]);
-				clk_enable(uart_fck[i]);
-			} else {
-				clk_disable(uart_ick[i]);
-				clk_disable(uart_fck[i]);
+	u16 lcr = 0;
+	struct plat_serial8250_port *p = uart->p;
+
+	if (!enable_off_mode)
+		return;
+
+	lcr = serial_read_reg(p, UART_LCR);
+	serial_write_reg(p, UART_LCR, 0xBF);
+	uart->dll = serial_read_reg(p, UART_DLL);
+	uart->dlh = serial_read_reg(p, UART_DLM);
+	serial_write_reg(p, UART_LCR, lcr);
+	uart->ier = serial_read_reg(p, UART_IER);
+	uart->sysc = serial_read_reg(p, UART_OMAP_SYSC);
+	uart->scr = serial_read_reg(p, UART_OMAP_SCR);
+	uart->wer = serial_read_reg(p, UART_OMAP_WER);
+
+	uart->context_valid = 1;
+}
+
+static void omap_uart_restore_context(struct omap_uart_state *uart)
+{
+	u16 efr = 0;
+	struct plat_serial8250_port *p = uart->p;
+
+	if (!enable_off_mode)
+		return;
+
+	if (!uart->context_valid)
+		return;
+
+	uart->context_valid = 0;
+
+	serial_write_reg(p, UART_OMAP_MDR1, 0x7);
+	serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
+	efr = serial_read_reg(p, UART_EFR);
+	serial_write_reg(p, UART_EFR, UART_EFR_ECB);
+	serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
+	serial_write_reg(p, UART_IER, 0x0);
+	serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
+	serial_write_reg(p, UART_DLL, uart->dll);
+	serial_write_reg(p, UART_DLM, uart->dlh);
+	serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
+	serial_write_reg(p, UART_IER, uart->ier);
+	serial_write_reg(p, UART_FCR, 0xA1);
+	serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
+	serial_write_reg(p, UART_EFR, efr);
+	serial_write_reg(p, UART_LCR, UART_LCR_WLEN8);
+	serial_write_reg(p, UART_OMAP_SCR, uart->scr);
+	serial_write_reg(p, UART_OMAP_WER, uart->wer);
+	serial_write_reg(p, UART_OMAP_SYSC, uart->sysc);
+	serial_write_reg(p, UART_OMAP_MDR1, 0x00); /* UART 16x mode */
+}
+#else
+static inline void omap_uart_save_context(struct omap_uart_state *uart) {}
+static inline void omap_uart_restore_context(struct omap_uart_state *uart) {}
+#endif /* CONFIG_PM && CONFIG_ARCH_OMAP3 */
+
+static inline void omap_uart_enable_clocks(struct omap_uart_state *uart)
+{
+	if (uart->clocked)
+		return;
+
+	clk_enable(uart->ick);
+	clk_enable(uart->fck);
+	uart->clocked = 1;
+	omap_uart_restore_context(uart);
+}
+
+#ifdef CONFIG_PM
+
+static inline void omap_uart_disable_clocks(struct omap_uart_state *uart)
+{
+	if (!uart->clocked)
+		return;
+
+	omap_uart_save_context(uart);
+	uart->clocked = 0;
+	clk_disable(uart->ick);
+	clk_disable(uart->fck);
+}
+
+static void omap_uart_smart_idle_enable(struct omap_uart_state *uart,
+					  int enable)
+{
+	struct plat_serial8250_port *p = uart->p;
+	u16 sysc;
+
+	sysc = serial_read_reg(p, UART_OMAP_SYSC) & 0x7;
+	if (enable)
+		sysc |= 0x2 << 3;
+	else
+		sysc |= 0x1 << 3;
+
+	serial_write_reg(p, UART_OMAP_SYSC, sysc);
+}
+
+static void omap_uart_block_sleep(struct omap_uart_state *uart)
+{
+	omap_uart_enable_clocks(uart);
+
+	omap_uart_smart_idle_enable(uart, 0);
+	uart->can_sleep = 0;
+	mod_timer(&uart->timer, jiffies + uart->timeout);
+}
+
+static void omap_uart_allow_sleep(struct omap_uart_state *uart)
+{
+	if (!uart->clocked)
+		return;
+
+	omap_uart_smart_idle_enable(uart, 1);
+	uart->can_sleep = 1;
+	del_timer(&uart->timer);
+}
+
+static void omap_uart_idle_timer(unsigned long data)
+{
+	struct omap_uart_state *uart = (struct omap_uart_state *)data;
+
+	omap_uart_allow_sleep(uart);
+}
+
+void omap_uart_prepare_idle(int num)
+{
+	struct omap_uart_state *uart;
+
+	list_for_each_entry(uart, &uart_list, node) {
+		if (!clocks_off_while_idle)
+			continue;
+
+		if (num == uart->num && uart->can_sleep) {
+			omap_uart_disable_clocks(uart);
+			return;
+		}
+	}
+}
+
+void omap_uart_resume_idle(int num)
+{
+	struct omap_uart_state *uart;
+
+	list_for_each_entry(uart, &uart_list, node) {
+		if (num == uart->num) {
+			omap_uart_enable_clocks(uart);
+
+			/* Check for IO pad wakeup */
+			if (cpu_is_omap34xx() && uart->padconf) {
+				u16 p = omap_ctrl_readw(uart->padconf);
+
+				if (p & OMAP3_PADCONF_WAKEUPEVENT0)
+					omap_uart_block_sleep(uart);
 			}
+
+			/* Check for normal UART wakeup */
+			if (__raw_readl(uart->wk_st) & uart->wk_mask)
+				omap_uart_block_sleep(uart);
+
+			return;
+		}
+	}
+}
+
+void omap_uart_prepare_suspend(void)
+{
+	struct omap_uart_state *uart;
+
+	list_for_each_entry(uart, &uart_list, node) {
+		omap_uart_allow_sleep(uart);
+	}
+}
+
+int omap_uart_can_sleep(void)
+{
+	struct omap_uart_state *uart;
+	int can_sleep = 1;
+
+	list_for_each_entry(uart, &uart_list, node) {
+		if (!uart->clocked)
+			continue;
+
+		if (!uart->can_sleep) {
+			can_sleep = 0;
+			continue;
 		}
+
+		/* This UART can now safely sleep. */
+		omap_uart_allow_sleep(uart);
 	}
+
+	return can_sleep;
 }
 
+/**
+ * omap_uart_interrupt()
+ *
+ * This handler is used only to detect that *any* UART interrupt has
+ * occurred.  It does _nothing_ to handle the interrupt.  Rather,
+ * any UART interrupt will trigger the inactivity timer so the
+ * UART will not idle or sleep for its timeout period.
+ *
+ **/
+static irqreturn_t omap_uart_interrupt(int irq, void *dev_id)
+{
+	struct omap_uart_state *uart = dev_id;
+
+	omap_uart_block_sleep(uart);
+
+	return IRQ_NONE;
+}
+
+static void omap_uart_idle_init(struct omap_uart_state *uart)
+{
+	u32 v;
+	struct plat_serial8250_port *p = uart->p;
+	int ret;
+
+	uart->can_sleep = 0;
+	uart->timeout = DEFAULT_TIMEOUT;
+	setup_timer(&uart->timer, omap_uart_idle_timer,
+		    (unsigned long) uart);
+	mod_timer(&uart->timer, jiffies + uart->timeout);
+	omap_uart_smart_idle_enable(uart, 0);
+
+	if (cpu_is_omap34xx()) {
+		u32 mod = (uart->num == 2) ? OMAP3430_PER_MOD : CORE_MOD;
+		u32 wk_mask = 0;
+		u32 padconf = 0;
+
+		uart->wk_en = OMAP34XX_PRM_REGADDR(mod, PM_WKEN1);
+		uart->wk_st = OMAP34XX_PRM_REGADDR(mod, PM_WKST1);
+		switch (uart->num) {
+		case 0:
+			wk_mask = OMAP3430_ST_UART1_MASK;
+			padconf = 0x182;
+			break;
+		case 1:
+			wk_mask = OMAP3430_ST_UART2_MASK;
+			padconf = 0x17a;
+			break;
+		case 2:
+			wk_mask = OMAP3430_ST_UART3_MASK;
+			padconf = 0x19e;
+			break;
+		}
+		uart->wk_mask = wk_mask;
+		uart->padconf = padconf;
+	} else if (cpu_is_omap24xx()) {
+		u32 wk_mask = 0;
+
+		if (cpu_is_omap2430()) {
+			uart->wk_en = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKEN1);
+			uart->wk_st = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKST1);
+		} else if (cpu_is_omap2420()) {
+			uart->wk_en = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKEN1);
+			uart->wk_st = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKST1);
+		}
+		switch (uart->num) {
+		case 0:
+			wk_mask = OMAP24XX_ST_UART1_MASK;
+			break;
+		case 1:
+			wk_mask = OMAP24XX_ST_UART2_MASK;
+			break;
+		case 2:
+			wk_mask = OMAP24XX_ST_UART3_MASK;
+			break;
+		}
+		uart->wk_mask = wk_mask;
+	} else {
+		uart->wk_en = 0;
+		uart->wk_st = 0;
+		uart->wk_mask = 0;
+		uart->padconf = 0;
+	}
+
+	/* Set wake-enable bit */
+	if (uart->wk_en && uart->wk_mask) {
+		v = __raw_readl(uart->wk_en);
+		v |= uart->wk_mask;
+		__raw_writel(v, uart->wk_en);
+	}
+
+	/* Ensure IOPAD wake-enables are set */
+	if (cpu_is_omap34xx() && uart->padconf) {
+		u16 v;
+
+		v = omap_ctrl_readw(uart->padconf);
+		v |= OMAP3_PADCONF_WAKEUPENABLE0;
+		omap_ctrl_writew(v, uart->padconf);
+	}
+
+	p->flags |= UPF_SHARE_IRQ;
+	ret = request_irq(p->irq, omap_uart_interrupt, IRQF_SHARED,
+			  "serial idle", (void *)uart);
+	WARN_ON(ret);
+}
+
+#else
+static inline void omap_uart_idle_init(struct omap_uart_state *uart) {}
+#endif /* CONFIG_PM */
+
 void __init omap_serial_init(void)
 {
 	int i;
@@ -117,6 +451,7 @@ void __init omap_serial_init(void)
 
 	for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
 		struct plat_serial8250_port *p = serial_platform_data + i;
+		struct omap_uart_state *uart = &omap_uart[i];
 
 		if (!(info->enabled_uarts & (1 << i))) {
 			p->membase = NULL;
@@ -125,22 +460,30 @@ void __init omap_serial_init(void)
 		}
 
 		sprintf(name, "uart%d_ick", i+1);
-		uart_ick[i] = clk_get(NULL, name);
-		if (IS_ERR(uart_ick[i])) {
+		uart->ick = clk_get(NULL, name);
+		if (IS_ERR(uart->ick)) {
 			printk(KERN_ERR "Could not get uart%d_ick\n", i+1);
-			uart_ick[i] = NULL;
-		} else
-			clk_enable(uart_ick[i]);
+			uart->ick = NULL;
+		}
 
 		sprintf(name, "uart%d_fck", i+1);
-		uart_fck[i] = clk_get(NULL, name);
-		if (IS_ERR(uart_fck[i])) {
+		uart->fck = clk_get(NULL, name);
+		if (IS_ERR(uart->fck)) {
 			printk(KERN_ERR "Could not get uart%d_fck\n", i+1);
-			uart_fck[i] = NULL;
-		} else
-			clk_enable(uart_fck[i]);
+			uart->fck = NULL;
+		}
+
+		if (!uart->ick || !uart->fck)
+			continue;
+
+		uart->num = i;
+		p->private_data = uart;
+		uart->p = p;
+		list_add(&uart->node, &uart_list);
 
-		omap_serial_reset(p);
+		omap_uart_enable_clocks(uart);
+		omap_uart_reset(uart);
+		omap_uart_idle_init(uart);
 	}
 }
 
diff --git a/arch/arm/plat-omap/include/mach/common.h b/arch/arm/plat-omap/include/mach/common.h
index 0ecf36d..834f0b3 100644
--- a/arch/arm/plat-omap/include/mach/common.h
+++ b/arch/arm/plat-omap/include/mach/common.h
@@ -33,8 +33,6 @@ struct sys_timer;
 
 extern void omap_map_common_io(void);
 extern struct sys_timer omap_timer;
-extern void omap_serial_init(void);
-extern void omap_serial_enable_clocks(int enable);
 #if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
 extern int omap_register_i2c_bus(int bus_id, u32 clkrate,
 				 struct i2c_board_info const *info,
diff --git a/arch/arm/plat-omap/include/mach/serial.h b/arch/arm/plat-omap/include/mach/serial.h
index 8a676a0..8e89585 100644
--- a/arch/arm/plat-omap/include/mach/serial.h
+++ b/arch/arm/plat-omap/include/mach/serial.h
@@ -40,4 +40,13 @@
 			__ret;						\
 			})
 
+#ifndef __ASSEMBLER__
+extern void omap_serial_init(void);
+extern int omap_uart_can_sleep(void);
+extern void omap_uart_check_wakeup(void);
+extern void omap_uart_prepare_suspend(void);
+extern void omap_uart_prepare_idle(int num);
+extern void omap_uart_resume_idle(int num);
+#endif
+
 #endif
-- 
1.6.2.2


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

* [PATCH 06/11] OMAP3: PM: Add D2D clocks and auto-idle setup to PRCM init
  2009-05-15 18:40         ` [PATCH 05/11] OMAP3: PM: UART: disable clocks when idle and off-mode support Kevin Hilman
@ 2009-05-15 18:40           ` Kevin Hilman
  2009-05-15 18:40             ` [PATCH 07/11] OMAP3: PM: D2D clockdomain supports SW supervised transitions Kevin Hilman
  0 siblings, 1 reply; 31+ messages in thread
From: Kevin Hilman @ 2009-05-15 18:40 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: linux-omap, Kevin Hilman

Add D2D clocks (modem_fck, sad2d_ick, mad2d_ick) to clock framework
and ensure that auto-idle bits are set for these clocks during PRCM
init.

Also add omap3_d2d_idle() function called durint PRCM setup which
ensures D2D pins are MUX'd correctly to enable retention for
standalone (no-modem) devices.

Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
 arch/arm/mach-omap2/clock34xx.c           |    3 ++
 arch/arm/mach-omap2/clock34xx.h           |   33 +++++++++++++++++++++++++++-
 arch/arm/mach-omap2/cm-regbits-34xx.h     |   14 ++++++++++++
 arch/arm/mach-omap2/pm34xx.c              |   25 ++++++++++++++++++++-
 arch/arm/plat-omap/include/mach/control.h |    4 +++
 5 files changed, 75 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c
index ba05aa4..13a36cf 100644
--- a/arch/arm/mach-omap2/clock34xx.c
+++ b/arch/arm/mach-omap2/clock34xx.c
@@ -129,6 +129,9 @@ static struct omap_clk omap34xx_clks[] = {
 	CLK(NULL,	"sgx_fck",	&sgx_fck,	CK_3430ES2),
 	CLK(NULL,	"sgx_ick",	&sgx_ick,	CK_3430ES2),
 	CLK(NULL,	"d2d_26m_fck",	&d2d_26m_fck,	CK_3430ES1),
+	CLK(NULL,	"modem_fck",	&modem_fck,	CK_343X),
+	CLK(NULL,	"sad2d_ick",	&sad2d_ick,	CK_343X),
+	CLK(NULL,	"mad2d_ick",	&mad2d_ick,	CK_343X),
 	CLK(NULL,	"gpt10_fck",	&gpt10_fck,	CK_343X),
 	CLK(NULL,	"gpt11_fck",	&gpt11_fck,	CK_343X),
 	CLK(NULL,	"cpefuse_fck",	&cpefuse_fck,	CK_3430ES2),
diff --git a/arch/arm/mach-omap2/clock34xx.h b/arch/arm/mach-omap2/clock34xx.h
index 496f0e9..e433aec 100644
--- a/arch/arm/mach-omap2/clock34xx.h
+++ b/arch/arm/mach-omap2/clock34xx.h
@@ -1230,6 +1230,37 @@ static struct clk d2d_26m_fck = {
 	.recalc		= &followparent_recalc,
 };
 
+static struct clk modem_fck = {
+	.name		= "modem_fck",
+	.ops		= &clkops_omap2_dflt_wait,
+	.parent		= &sys_ck,
+	.init		= &omap2_init_clk_clkdm,
+	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+	.enable_bit	= OMAP3430_EN_MODEM_SHIFT,
+	.clkdm_name	= "d2d_clkdm",
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk sad2d_ick = {
+	.name		= "sad2d_ick",
+	.ops		= &clkops_omap2_dflt_wait,
+	.parent		= &l3_ick,
+	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+	.enable_bit	= OMAP3430_EN_SAD2D_SHIFT,
+	.clkdm_name	= "d2d_clkdm",
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk mad2d_ick = {
+	.name		= "mad2d_ick",
+	.ops		= &clkops_omap2_dflt_wait,
+	.parent		= &l3_ick,
+	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
+	.enable_bit	= OMAP3430_EN_MAD2D_SHIFT,
+	.clkdm_name	= "d2d_clkdm",
+	.recalc		= &followparent_recalc,
+};
+
 static const struct clksel omap343x_gpt_clksel[] = {
 	{ .parent = &omap_32k_fck, .rates = gpt_32k_rates },
 	{ .parent = &sys_ck,	   .rates = gpt_sys_rates },
@@ -1947,8 +1978,6 @@ static struct clk usb_l4_ick = {
 	.recalc		= &omap2_clksel_recalc,
 };
 
-/* XXX MDM_INTC_ICK, SAD2D_ICK ?? */
-
 /* SECURITY_L4_ICK2 based clocks */
 
 static struct clk security_l4_ick2 = {
diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h
index 6f3f5a3..6923deb 100644
--- a/arch/arm/mach-omap2/cm-regbits-34xx.h
+++ b/arch/arm/mach-omap2/cm-regbits-34xx.h
@@ -145,6 +145,8 @@
 #define OMAP3430_CLKACTIVITY_MPU_MASK			(1 << 0)
 
 /* CM_FCLKEN1_CORE specific bits */
+#define OMAP3430_EN_MODEM				(1 << 31)
+#define OMAP3430_EN_MODEM_SHIFT				31
 
 /* CM_ICLKEN1_CORE specific bits */
 #define OMAP3430_EN_ICR					(1 << 29)
@@ -161,6 +163,8 @@
 #define OMAP3430_EN_MAILBOXES_SHIFT			7
 #define OMAP3430_EN_OMAPCTRL				(1 << 6)
 #define OMAP3430_EN_OMAPCTRL_SHIFT			6
+#define OMAP3430_EN_SAD2D				(1 << 3)
+#define OMAP3430_EN_SAD2D_SHIFT				3
 #define OMAP3430_EN_SDRC				(1 << 1)
 #define OMAP3430_EN_SDRC_SHIFT				1
 
@@ -176,6 +180,10 @@
 #define OMAP3430_EN_DES1				(1 << 0)
 #define OMAP3430_EN_DES1_SHIFT				0
 
+/* CM_ICLKEN3_CORE */
+#define OMAP3430_EN_MAD2D_SHIFT				3
+#define OMAP3430_EN_MAD2D				(1 << 3)
+
 /* CM_FCLKEN3_CORE specific bits */
 #define OMAP3430ES2_EN_TS_SHIFT				1
 #define OMAP3430ES2_EN_TS_MASK				(1 << 1)
@@ -231,6 +239,8 @@
 #define OMAP3430ES2_ST_CPEFUSE_MASK			(1 << 0)
 
 /* CM_AUTOIDLE1_CORE */
+#define OMAP3430_AUTO_MODEM				(1 << 31)
+#define OMAP3430_AUTO_MODEM_SHIFT			31
 #define OMAP3430ES2_AUTO_MMC3				(1 << 30)
 #define OMAP3430ES2_AUTO_MMC3_SHIFT			30
 #define OMAP3430ES2_AUTO_ICR				(1 << 29)
@@ -287,6 +297,8 @@
 #define OMAP3430_AUTO_HSOTGUSB_SHIFT			4
 #define OMAP3430ES1_AUTO_D2D				(1 << 3)
 #define OMAP3430ES1_AUTO_D2D_SHIFT			3
+#define OMAP3430_AUTO_SAD2D				(1 << 3)
+#define OMAP3430_AUTO_SAD2D_SHIFT			3
 #define OMAP3430_AUTO_SSI				(1 << 0)
 #define OMAP3430_AUTO_SSI_SHIFT				0
 
@@ -308,6 +320,8 @@
 #define	OMAP3430ES2_AUTO_USBTLL				(1 << 2)
 #define OMAP3430ES2_AUTO_USBTLL_SHIFT			2
 #define OMAP3430ES2_AUTO_USBTLL_MASK			(1 << 2)
+#define OMAP3430_AUTO_MAD2D_SHIFT			3
+#define OMAP3430_AUTO_MAD2D				(1 << 3)
 
 /* CM_CLKSEL_CORE */
 #define OMAP3430_CLKSEL_SSI_SHIFT			8
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 24a146c..a7734c7 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -421,14 +421,32 @@ static void __init omap3_iva_idle(void)
 			  OMAP3430_IVA2_MOD, RM_RSTCTRL);
 }
 
-static void __init prcm_setup_regs(void)
+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 */
 	prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON |
 			  OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST,
 			  CORE_MOD, RM_RSTCTRL);
 	prm_write_mod_reg(0, CORE_MOD, RM_RSTCTRL);
+}
 
+static void __init prcm_setup_regs(void)
+{
 	/* XXX Reset all wkdeps. This should be done when initializing
 	 * powerdomains */
 	prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
@@ -448,6 +466,7 @@ static void __init prcm_setup_regs(void)
 	 * Note that in the long run this should be done by clockfw
 	 */
 	cm_write_mod_reg(
+		OMAP3430_AUTO_MODEM |
 		OMAP3430ES2_AUTO_MMC3 |
 		OMAP3430ES2_AUTO_ICR |
 		OMAP3430_AUTO_AES2 |
@@ -475,7 +494,7 @@ static void __init prcm_setup_regs(void)
 		OMAP3430_AUTO_OMAPCTRL |
 		OMAP3430ES1_AUTO_FSHOSTUSB |
 		OMAP3430_AUTO_HSOTGUSB |
-		OMAP3430ES1_AUTO_D2D | /* This is es1 only */
+		OMAP3430_AUTO_SAD2D |
 		OMAP3430_AUTO_SSI,
 		CORE_MOD, CM_AUTOIDLE1);
 
@@ -489,6 +508,7 @@ static void __init prcm_setup_regs(void)
 
 	if (omap_rev() > OMAP3430_REV_ES1_0) {
 		cm_write_mod_reg(
+			OMAP3430_AUTO_MAD2D |
 			OMAP3430ES2_AUTO_USBTLL,
 			CORE_MOD, CM_AUTOIDLE3);
 	}
@@ -582,6 +602,7 @@ static void __init prcm_setup_regs(void)
 			  OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
 
 	omap3_iva_idle();
+	omap3_d2d_idle();
 }
 
 static int __init pwrdms_setup(struct powerdomain *pwrdm)
diff --git a/arch/arm/plat-omap/include/mach/control.h b/arch/arm/plat-omap/include/mach/control.h
index a9f05e5..fcc5a9b 100644
--- a/arch/arm/plat-omap/include/mach/control.h
+++ b/arch/arm/plat-omap/include/mach/control.h
@@ -144,6 +144,10 @@
 #define OMAP343X_CONTROL_PBIAS_LITE	(OMAP2_CONTROL_GENERAL + 0x02b0)
 #define OMAP343X_CONTROL_TEMP_SENSOR	(OMAP2_CONTROL_GENERAL + 0x02b4)
 
+/* 34xx D2D idle-related pins, handled by PM core */
+#define OMAP3_PADCONF_SAD2D_MSTANDBY   0x250
+#define OMAP3_PADCONF_SAD2D_IDLEACK    0x254
+
 /*
  * REVISIT: This list of registers is not comprehensive - there are more
  * that should be added.
-- 
1.6.2.2


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

* [PATCH 07/11] OMAP3: PM: D2D clockdomain supports SW supervised transitions
  2009-05-15 18:40           ` [PATCH 06/11] OMAP3: PM: Add D2D clocks and auto-idle setup to PRCM init Kevin Hilman
@ 2009-05-15 18:40             ` Kevin Hilman
  2009-05-15 18:40               ` [PATCH 08/11] OMAP3: PM: Ensure MUSB block can idle when driver not loaded Kevin Hilman
  0 siblings, 1 reply; 31+ messages in thread
From: Kevin Hilman @ 2009-05-15 18:40 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: linux-omap, Kevin Hilman

Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
 arch/arm/mach-omap2/clockdomains.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h
index 281d5da..fe319ae 100644
--- a/arch/arm/mach-omap2/clockdomains.h
+++ b/arch/arm/mach-omap2/clockdomains.h
@@ -195,7 +195,7 @@ static struct clockdomain sgx_clkdm = {
 static struct clockdomain d2d_clkdm = {
 	.name		= "d2d_clkdm",
 	.pwrdm		= { .name = "core_pwrdm" },
-	.flags		= CLKDM_CAN_HWSUP,
+	.flags		= CLKDM_CAN_HWSUP_SWSUP,
 	.clktrctrl_mask = OMAP3430ES1_CLKTRCTRL_D2D_MASK,
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
 };
-- 
1.6.2.2


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

* [PATCH 08/11] OMAP3: PM: Ensure MUSB block can idle when driver not loaded
  2009-05-15 18:40             ` [PATCH 07/11] OMAP3: PM: D2D clockdomain supports SW supervised transitions Kevin Hilman
@ 2009-05-15 18:40               ` Kevin Hilman
  2009-05-15 18:40                 ` [PATCH 09/11] OMAP3: PM: Ensure PRCM interrupts are cleared at boot Kevin Hilman
  2009-05-18 13:16                 ` [PATCH 08/11] OMAP3: PM: Ensure MUSB block can idle when driver not loaded Russell King - ARM Linux
  0 siblings, 2 replies; 31+ messages in thread
From: Kevin Hilman @ 2009-05-15 18:40 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-omap, Peter 'p2' De Schrijver, Kevin Hilman

From: Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com>

Otherwise, bootloaders may leave MUSB in a state which prevents
retention.

Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
 arch/arm/mach-omap2/usb-musb.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c
index 215d463..57e857e 100644
--- a/arch/arm/mach-omap2/usb-musb.c
+++ b/arch/arm/mach-omap2/usb-musb.c
@@ -31,6 +31,8 @@
 #include <mach/mux.h>
 #include <mach/usb.h>
 
+#define OTG_SYSCONFIG	(OMAP34XX_HSUSB_OTG_BASE + 0x404)
+
 static struct resource musb_resources[] = {
 	[0] = { /* start and end set dynamically */
 		.flags	= IORESOURCE_MEM,
@@ -183,4 +185,8 @@ void __init usb_musb_init(void)
 		printk(KERN_ERR "Unable to register HS-USB (MUSB) device\n");
 		return;
 	}
+
+	/* Ensure force-idle mode for OTG controller */
+	if (cpu_is_omap34xx())
+		omap_writel(0, OTG_SYSCONFIG);
 }
-- 
1.6.2.2


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

* [PATCH 09/11] OMAP3: PM: Ensure PRCM interrupts are cleared at boot
  2009-05-15 18:40               ` [PATCH 08/11] OMAP3: PM: Ensure MUSB block can idle when driver not loaded Kevin Hilman
@ 2009-05-15 18:40                 ` Kevin Hilman
  2009-05-15 18:40                   ` [PATCH 10/11] OMAP3: PM: Clear pending PRCM reset flags on init Kevin Hilman
  2009-05-18 13:16                 ` [PATCH 08/11] OMAP3: PM: Ensure MUSB block can idle when driver not loaded Russell King - ARM Linux
  1 sibling, 1 reply; 31+ messages in thread
From: Kevin Hilman @ 2009-05-15 18:40 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: linux-omap, Kevin Hilman

Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
 arch/arm/mach-omap2/pm34xx.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index a7734c7..9b29414 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -601,6 +601,9 @@ static void __init prcm_setup_regs(void)
 	prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
 			  OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
 
+	/* Clear any pending PRCM interrupts */
+	prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+
 	omap3_iva_idle();
 	omap3_d2d_idle();
 }
-- 
1.6.2.2


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

* [PATCH 10/11] OMAP3: PM: Clear pending PRCM reset flags on init
  2009-05-15 18:40                 ` [PATCH 09/11] OMAP3: PM: Ensure PRCM interrupts are cleared at boot Kevin Hilman
@ 2009-05-15 18:40                   ` Kevin Hilman
  2009-05-15 18:40                     ` [PATCH 11/11] OMAP3: PM: prevent module wakeups from waking IVA2 Kevin Hilman
  0 siblings, 1 reply; 31+ messages in thread
From: Kevin Hilman @ 2009-05-15 18:40 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: linux-omap, Kevin Hilman

Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
 arch/arm/mach-omap2/pm34xx.c |    9 +++++++++
 1 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 9b29414..7ed01e5 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -601,6 +601,15 @@ static void __init prcm_setup_regs(void)
 	prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
 			  OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
 
+	/* Clear any pending 'reset' flags */
+	prm_write_mod_reg(0xffffffff, MPU_MOD, RM_RSTST);
+	prm_write_mod_reg(0xffffffff, CORE_MOD, RM_RSTST);
+	prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, RM_RSTST);
+	prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, RM_RSTST);
+	prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, RM_RSTST);
+	prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, RM_RSTST);
+	prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, RM_RSTST);
+
 	/* Clear any pending PRCM interrupts */
 	prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
 
-- 
1.6.2.2


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

* [PATCH 11/11] OMAP3: PM: prevent module wakeups from waking IVA2
  2009-05-15 18:40                   ` [PATCH 10/11] OMAP3: PM: Clear pending PRCM reset flags on init Kevin Hilman
@ 2009-05-15 18:40                     ` Kevin Hilman
  0 siblings, 0 replies; 31+ messages in thread
From: Kevin Hilman @ 2009-05-15 18:40 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: linux-omap, Kevin Hilman

By default, prevent functional wakeups from inside a module from
waking up the IVA2.  Let DSP Bridge code handle this when loaded.

Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
 arch/arm/mach-omap2/pm34xx.c |    6 ++++++
 arch/arm/mach-omap2/prm.h    |    2 ++
 2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 7ed01e5..22d686e 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -601,6 +601,12 @@ static void __init prcm_setup_regs(void)
 	prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
 			  OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
 
+	/* Don't attach IVA interrupts */
+	prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL);
+	prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1);
+	prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3);
+	prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL);
+
 	/* Clear any pending 'reset' flags */
 	prm_write_mod_reg(0xffffffff, MPU_MOD, RM_RSTST);
 	prm_write_mod_reg(0xffffffff, CORE_MOD, RM_RSTST);
diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h
index 7c8e0c4..9937e28 100644
--- a/arch/arm/mach-omap2/prm.h
+++ b/arch/arm/mach-omap2/prm.h
@@ -203,9 +203,11 @@
 
 #define OMAP3430_PM_MPUGRPSEL				0x00a4
 #define OMAP3430_PM_MPUGRPSEL1				OMAP3430_PM_MPUGRPSEL
+#define OMAP3430ES2_PM_MPUGRPSEL3			0x00f8
 
 #define OMAP3430_PM_IVAGRPSEL				0x00a8
 #define OMAP3430_PM_IVAGRPSEL1				OMAP3430_PM_IVAGRPSEL
+#define OMAP3430ES2_PM_IVAGRPSEL3			0x00f4
 
 #define OMAP3430_PM_PREPWSTST				0x00e8
 
-- 
1.6.2.2


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

* Re: [PATCH 08/11] OMAP3: PM: Ensure MUSB block can idle when driver not loaded
  2009-05-15 18:40               ` [PATCH 08/11] OMAP3: PM: Ensure MUSB block can idle when driver not loaded Kevin Hilman
  2009-05-15 18:40                 ` [PATCH 09/11] OMAP3: PM: Ensure PRCM interrupts are cleared at boot Kevin Hilman
@ 2009-05-18 13:16                 ` Russell King - ARM Linux
  2009-05-18 14:50                   ` Kevin Hilman
  1 sibling, 1 reply; 31+ messages in thread
From: Russell King - ARM Linux @ 2009-05-18 13:16 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: linux-arm-kernel, linux-omap, Peter 'p2' De Schrijver

On Fri, May 15, 2009 at 11:40:48AM -0700, Kevin Hilman wrote:
> Otherwise, bootloaders may leave MUSB in a state which prevents
> retention.

Hmm, so what happens if a boot loader has touched this MUSB thing, but
the kernel which is being run doesn't have CONFIG_USB_MUSB_SOC enabled?

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

* Re: [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap
  2009-05-15 18:40 ` [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap Kevin Hilman
  2009-05-15 18:40   ` [PATCH 02/11] OMAP: Add new function to check wether there is irq pending Kevin Hilman
@ 2009-05-18 13:32   ` Russell King - ARM Linux
  2009-05-18 17:00     ` Kevin Hilman
  2009-05-18 17:08     ` Kevin Hilman
  1 sibling, 2 replies; 31+ messages in thread
From: Russell King - ARM Linux @ 2009-05-18 13:32 UTC (permalink / raw)
  To: Kevin Hilman; +Cc: linux-arm-kernel, linux-omap, Jouni Hogander, Paul Walmsley

On Fri, May 15, 2009 at 11:40:41AM -0700, Kevin Hilman wrote:
> This patch is to sync the core linux-omap PM code with mainline.  This
> code has evolved and been used for a while the linux-omap tree, but
> the attempt here is to finally get this into mainline.
> 
> Following this will be a series of patches from the 'PM branch' of the
> linux-omap tree to add full PM hardware support from the linux-omap
> tree.
> 
> Much of this PM core code was written by Jouni Hogander with
> significant contributions from Paul Walmsley as well as many others
> from Nokia, Texas Instruments and linux-omap community.

Overall comment, I think we need to rework the idle support code so
that enable_hlt/disable_hlt can be used even when pm_idle has been
overridden, rather than OMAP going off and inventing its own mechanisms.

> diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
> new file mode 100644
> index 0000000..2a2d1a3
> --- /dev/null
> +++ b/arch/arm/mach-omap2/pm24xx.c
> @@ -0,0 +1,557 @@
> +/*
> + * OMAP2 Power Management Routines
> + *
> + * Copyright (C) 2005 Texas Instruments, Inc.
> + * Copyright (C) 2006-2008 Nokia Corporation
> + *
> + * Written by:
> + * Richard Woodruff <r-woodruff2@ti.com>
> + * Tony Lindgren
> + * Juha Yrjola
> + * Amit Kucheria <amit.kucheria@nokia.com>
> + * Igor Stoppa <igor.stoppa@nokia.com>
> + *
> + * Based on pm.c for omap1
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/suspend.h>
> +#include <linux/sched.h>
> +#include <linux/proc_fs.h>
> +#include <linux/interrupt.h>
> +#include <linux/sysfs.h>
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/time.h>
> +
> +#include <asm/mach/time.h>
> +#include <asm/mach/irq.h>
> +#include <asm/mach-types.h>
> +
> +#include <mach/irqs.h>
> +#include <mach/clock.h>
> +#include <mach/sram.h>
> +#include <mach/control.h>
> +#include <mach/gpio.h>

Should be linux/gpio.h

> +/*
> + * Note that you can use clock_event_device->min_delta_ns if you want to
> + * avoid reprogramming timer too often when using CONFIG_NO_HZ.
> + */
> +static void omap2_pm_idle(void)
> +{
> +	local_irq_disable();
> +	local_fiq_disable();
> +
> +	if (!omap2_can_sleep()) {
> +		if (!atomic_read(&sleep_block) && omap2_irq_pending())
> +			goto out;
> +		omap2_enter_mpu_retention();
> +		goto out;
> +	}
> +
> +	if (omap2_irq_pending())
> +		goto out;
> +
> +	omap2_enter_full_retention();
> +
> +out:
> +	local_fiq_enable();
> +	local_irq_enable();
> +}

It's totally unclear what the comment above the function has to do with
the function itself.

> diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
> new file mode 100644
> index 0000000..0fb6bec
> --- /dev/null
> +++ b/arch/arm/mach-omap2/pm34xx.c
> @@ -0,0 +1,607 @@
> +/*
> + * OMAP3 Power Management Routines
> + *
> + * Copyright (C) 2006-2008 Nokia Corporation
> + * Tony Lindgren <tony@atomide.com>
> + * Jouni Hogander
> + *
> + * Copyright (C) 2005 Texas Instruments, Inc.
> + * Richard Woodruff <r-woodruff2@ti.com>
> + *
> + * Based on pm.c for omap1
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/pm.h>
> +#include <linux/suspend.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/list.h>
> +#include <linux/err.h>
> +
> +#include <mach/gpio.h>

Should be linux/gpio.h

> +static void omap3_pm_idle(void)
> +{
> +	local_irq_disable();
> +	local_fiq_disable();
> +
> +	if (!omap3_can_sleep())
> +		goto out;
> +
> +	if (omap_irq_pending())
> +		goto out;

So what happens if an IRQ becomes pending at this precise point?

> +
> +	omap_sram_idle();
> +
> +out:
> +	local_fiq_enable();
> +	local_irq_enable();
> +}
> +	/* IRQ mode */
> +	bic    r0, r7, #0x1F
> +	orr    r0, r0, #0x12
> +	msr    cpsr, r0	/*go into IRQ mode*/
> +	ldmia  r3!,{r4-r6}	/*load the SP and LR from SDRAM*/
> +	mov    sp, r4	/*update the SP */
> +	mov    lr, r5	/*update the LR */
> +	msr    spsr, r6	/*update the SPSR */
> +
> +	/* ABORT mode */
> +	bic    r0, r7, #0x1F
> +	orr    r0, r0, #0x17
> +	msr    cpsr, r0	/* go into ABORT mode */
> +	ldmia  r3!,{r4-r6}	/*load the SP and LR from SDRAM */
> +	mov    sp, r4		/*update the SP */
> +	mov    lr, r5		/*update the LR */
> +	msr    spsr, r6		/*update the SPSR */
> +
> +	/* UNDEEF mode */
> +	bic    r0, r7, #0x1F
> +	orr    r0, r0, #0x1B
> +	msr    cpsr, r0		/*go into UNDEF mode */
> +	ldmia  r3!,{r4-r6}	/*load the SP and LR from SDRAM */
> +	mov    sp, r4		/*update the SP*/
> +	mov    lr, r5		/*update the LR*/
> +	msr    spsr, r6		/*update the SPSR*/
> +
> +	/* SYSTEM (USER) mode */
> +	bic    r0, r7, #0x1F
> +	orr    r0, r0, #0x1F
> +	msr    cpsr, r0		/*go into USR mode */
> +	ldmia  r3!,{r4-r6}	/*load the SP and LR from SDRAM*/
> +	mov    sp, r4		/*update the SP */
> +	mov    lr, r5		/*update the LR */
> +	msr    spsr, r6		/*update the SPSR */
> +	msr    cpsr, r7		/*back to original mode*/

There is a function which re-initializes the abort mode registers already -
cpu_init().  Please use that if possible instead.

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

* Re: [PATCH 08/11] OMAP3: PM: Ensure MUSB block can idle when driver not loaded
  2009-05-18 13:16                 ` [PATCH 08/11] OMAP3: PM: Ensure MUSB block can idle when driver not loaded Russell King - ARM Linux
@ 2009-05-18 14:50                   ` Kevin Hilman
  2009-05-18 15:04                     ` Tony Lindgren
  0 siblings, 1 reply; 31+ messages in thread
From: Kevin Hilman @ 2009-05-18 14:50 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linux-arm-kernel, linux-omap, Peter 'p2' De Schrijver,
	Tony Lindgren

Russell King - ARM Linux <linux@arm.linux.org.uk> writes:

> On Fri, May 15, 2009 at 11:40:48AM -0700, Kevin Hilman wrote:
>> Otherwise, bootloaders may leave MUSB in a state which prevents
>> retention.
>
> Hmm, so what happens if a boot loader has touched this MUSB thing, but
> the kernel which is being run doesn't have CONFIG_USB_MUSB_SOC enabled?

Then the OMAP will not be able to hit retention.

That Makefile change happened after this series was initially made.
I think we should change the Makefile back to always compile usb-musb.c
and move the #ifdef CONFIG_USB_MUSB_SOC into usb-musb.c

Tony, any objections?

Kevin

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

* Re: [PATCH 08/11] OMAP3: PM: Ensure MUSB block can idle when driver not loaded
  2009-05-18 14:50                   ` Kevin Hilman
@ 2009-05-18 15:04                     ` Tony Lindgren
  0 siblings, 0 replies; 31+ messages in thread
From: Tony Lindgren @ 2009-05-18 15:04 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Russell King - ARM Linux, linux-arm-kernel, linux-omap,
	Peter 'p2' De Schrijver

* Kevin Hilman <khilman@deeprootsystems.com> [090518 07:50]:
> Russell King - ARM Linux <linux@arm.linux.org.uk> writes:
> 
> > On Fri, May 15, 2009 at 11:40:48AM -0700, Kevin Hilman wrote:
> >> Otherwise, bootloaders may leave MUSB in a state which prevents
> >> retention.
> >
> > Hmm, so what happens if a boot loader has touched this MUSB thing, but
> > the kernel which is being run doesn't have CONFIG_USB_MUSB_SOC enabled?
> 
> Then the OMAP will not be able to hit retention.
> 
> That Makefile change happened after this series was initially made.
> I think we should change the Makefile back to always compile usb-musb.c
> and move the #ifdef CONFIG_USB_MUSB_SOC into usb-musb.c
> 
> Tony, any objections?

Sounds good to me, I like patches that make things behave in a predictable
way.

We already have enough of these mysterious problems where "the same kernel
behaves in a different way on my board" when some registers are only
tweaked in the bootloader.

Regards,

Tony

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

* Re: [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap
  2009-05-18 13:32   ` [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap Russell King - ARM Linux
@ 2009-05-18 17:00     ` Kevin Hilman
  2009-05-18 17:06       ` Russell King - ARM Linux
  2009-05-18 17:08     ` Kevin Hilman
  1 sibling, 1 reply; 31+ messages in thread
From: Kevin Hilman @ 2009-05-18 17:00 UTC (permalink / raw)
  To: Russell King - ARM Linux, Richard Woodruff
  Cc: linux-arm-kernel, linux-omap, Jouni Hogander, Paul Walmsley

Russell King - ARM Linux <linux@arm.linux.org.uk> writes:

> On Fri, May 15, 2009 at 11:40:41AM -0700, Kevin Hilman wrote:
>> This patch is to sync the core linux-omap PM code with mainline.  This
>> code has evolved and been used for a while the linux-omap tree, but
>> the attempt here is to finally get this into mainline.
>> 
>> Following this will be a series of patches from the 'PM branch' of the
>> linux-omap tree to add full PM hardware support from the linux-omap
>> tree.
>> 
>> Much of this PM core code was written by Jouni Hogander with
>> significant contributions from Paul Walmsley as well as many others
>> from Nokia, Texas Instruments and linux-omap community.
>
> Overall comment, I think we need to rework the idle support code so
> that enable_hlt/disable_hlt can be used even when pm_idle has been
> overridden, rather than OMAP going off and inventing its own mechanisms.

Would adding:

	if (hlt_counter)
		cpu_relax();

to the beginning of omap*_pm_idle functions be sufficient?  That will
at least allow the hlt stuff to behave as expected.

The only thing the OMAP /sys/power/sleep_while_idle hook adds to this
functionality is the ability to control this from sysfs.

Any objections to /sys/power/enable_hlt?

>> diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
>> new file mode 100644
>> index 0000000..2a2d1a3
>> --- /dev/null
>> +++ b/arch/arm/mach-omap2/pm24xx.c
>> @@ -0,0 +1,557 @@
>> +/*
>> + * OMAP2 Power Management Routines
>> + *
>> + * Copyright (C) 2005 Texas Instruments, Inc.
>> + * Copyright (C) 2006-2008 Nokia Corporation
>> + *
>> + * Written by:
>> + * Richard Woodruff <r-woodruff2@ti.com>
>> + * Tony Lindgren
>> + * Juha Yrjola
>> + * Amit Kucheria <amit.kucheria@nokia.com>
>> + * Igor Stoppa <igor.stoppa@nokia.com>
>> + *
>> + * Based on pm.c for omap1
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/suspend.h>
>> +#include <linux/sched.h>
>> +#include <linux/proc_fs.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/sysfs.h>
>> +#include <linux/module.h>
>> +#include <linux/delay.h>
>> +#include <linux/clk.h>
>> +#include <linux/io.h>
>> +#include <linux/irq.h>
>> +#include <linux/time.h>
>> +
>> +#include <asm/mach/time.h>
>> +#include <asm/mach/irq.h>
>> +#include <asm/mach-types.h>
>> +
>> +#include <mach/irqs.h>
>> +#include <mach/clock.h>
>> +#include <mach/sram.h>
>> +#include <mach/control.h>
>> +#include <mach/gpio.h>
>
> Should be linux/gpio.h

Ack

>> +/*
>> + * Note that you can use clock_event_device->min_delta_ns if you want to
>> + * avoid reprogramming timer too often when using CONFIG_NO_HZ.
>> + */
>> +static void omap2_pm_idle(void)
>> +{
>> +	local_irq_disable();
>> +	local_fiq_disable();
>> +
>> +	if (!omap2_can_sleep()) {
>> +		if (!atomic_read(&sleep_block) && omap2_irq_pending())
>> +			goto out;
>> +		omap2_enter_mpu_retention();
>> +		goto out;
>> +	}
>> +
>> +	if (omap2_irq_pending())
>> +		goto out;
>> +
>> +	omap2_enter_full_retention();
>> +
>> +out:
>> +	local_fiq_enable();
>> +	local_irq_enable();
>> +}
>
> It's totally unclear what the comment above the function has to do with
> the function itself.

Indeed.  Will be removed.

>> diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
>> new file mode 100644
>> index 0000000..0fb6bec
>> --- /dev/null
>> +++ b/arch/arm/mach-omap2/pm34xx.c
>> @@ -0,0 +1,607 @@
>> +/*
>> + * OMAP3 Power Management Routines
>> + *
>> + * Copyright (C) 2006-2008 Nokia Corporation
>> + * Tony Lindgren <tony@atomide.com>
>> + * Jouni Hogander
>> + *
>> + * Copyright (C) 2005 Texas Instruments, Inc.
>> + * Richard Woodruff <r-woodruff2@ti.com>
>> + *
>> + * Based on pm.c for omap1
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/pm.h>
>> +#include <linux/suspend.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/module.h>
>> +#include <linux/list.h>
>> +#include <linux/err.h>
>> +
>> +#include <mach/gpio.h>
>
> Should be linux/gpio.h

Ack

>> +static void omap3_pm_idle(void)
>> +{
>> +	local_irq_disable();
>> +	local_fiq_disable();
>> +
>> +	if (!omap3_can_sleep())
>> +		goto out;
>> +
>> +	if (omap_irq_pending())
>> +		goto out;
>
> So what happens if an IRQ becomes pending at this precise point?

Then it gets missed this time, and will be triggered upon wakeup.  If
it's a wakeup-capable interrupt, then it will wake the system
immediately.

In subsequent series of the PM branch, this will be going away in
favor of using the [enable|disable]_irq_wake() and the lazy IRQ
disabling features.

>> +
>> +	omap_sram_idle();
>> +
>> +out:
>> +	local_fiq_enable();
>> +	local_irq_enable();
>> +}
>> +	/* IRQ mode */
>> +	bic    r0, r7, #0x1F
>> +	orr    r0, r0, #0x12
>> +	msr    cpsr, r0	/*go into IRQ mode*/
>> +	ldmia  r3!,{r4-r6}	/*load the SP and LR from SDRAM*/
>> +	mov    sp, r4	/*update the SP */
>> +	mov    lr, r5	/*update the LR */
>> +	msr    spsr, r6	/*update the SPSR */
>> +
>> +	/* ABORT mode */
>> +	bic    r0, r7, #0x1F
>> +	orr    r0, r0, #0x17
>> +	msr    cpsr, r0	/* go into ABORT mode */
>> +	ldmia  r3!,{r4-r6}	/*load the SP and LR from SDRAM */
>> +	mov    sp, r4		/*update the SP */
>> +	mov    lr, r5		/*update the LR */
>> +	msr    spsr, r6		/*update the SPSR */
>> +
>> +	/* UNDEEF mode */
>> +	bic    r0, r7, #0x1F
>> +	orr    r0, r0, #0x1B
>> +	msr    cpsr, r0		/*go into UNDEF mode */
>> +	ldmia  r3!,{r4-r6}	/*load the SP and LR from SDRAM */
>> +	mov    sp, r4		/*update the SP*/
>> +	mov    lr, r5		/*update the LR*/
>> +	msr    spsr, r6		/*update the SPSR*/
>> +
>> +	/* SYSTEM (USER) mode */
>> +	bic    r0, r7, #0x1F
>> +	orr    r0, r0, #0x1F
>> +	msr    cpsr, r0		/*go into USR mode */
>> +	ldmia  r3!,{r4-r6}	/*load the SP and LR from SDRAM*/
>> +	mov    sp, r4		/*update the SP */
>> +	mov    lr, r5		/*update the LR */
>> +	msr    spsr, r6		/*update the SPSR */
>> +	msr    cpsr, r7		/*back to original mode*/
>
> There is a function which re-initializes the abort mode registers already -
> cpu_init().  Please use that if possible instead.

OK, will investigate.

Kevin

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

* Re: [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap
  2009-05-18 17:00     ` Kevin Hilman
@ 2009-05-18 17:06       ` Russell King - ARM Linux
  2009-05-18 17:28         ` Kevin Hilman
  2009-05-19 18:55         ` Kevin Hilman
  0 siblings, 2 replies; 31+ messages in thread
From: Russell King - ARM Linux @ 2009-05-18 17:06 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Richard Woodruff, linux-arm-kernel, linux-omap, Jouni Hogander,
	Paul Walmsley

On Mon, May 18, 2009 at 10:00:44AM -0700, Kevin Hilman wrote:
> Russell King - ARM Linux <linux@arm.linux.org.uk> writes:
> 
> > On Fri, May 15, 2009 at 11:40:41AM -0700, Kevin Hilman wrote:
> >> This patch is to sync the core linux-omap PM code with mainline.  This
> >> code has evolved and been used for a while the linux-omap tree, but
> >> the attempt here is to finally get this into mainline.
> >> 
> >> Following this will be a series of patches from the 'PM branch' of the
> >> linux-omap tree to add full PM hardware support from the linux-omap
> >> tree.
> >> 
> >> Much of this PM core code was written by Jouni Hogander with
> >> significant contributions from Paul Walmsley as well as many others
> >> from Nokia, Texas Instruments and linux-omap community.
> >
> > Overall comment, I think we need to rework the idle support code so
> > that enable_hlt/disable_hlt can be used even when pm_idle has been
> > overridden, rather than OMAP going off and inventing its own mechanisms.
> 
> Would adding:
> 
> 	if (hlt_counter)
> 		cpu_relax();
> 
> to the beginning of omap*_pm_idle functions be sufficient?  That will
> at least allow the hlt stuff to behave as expected.

Yes, but the comment was also directed at the other functions which
increment/decrement that atomic_t variable to enable/disable sleep mode.

> The only thing the OMAP /sys/power/sleep_while_idle hook adds to this
> functionality is the ability to control this from sysfs.
> 
> Any objections to /sys/power/enable_hlt?

That seems to be rather dangerous, even with your atomic based code which
bugs if the count goes below zero.

The problem here is that such an interface is extremely fragile.  Consider
what happens if a program disables HLT, and then gets killed off for some
reason.  How does this reference get balanced again?

I think a better solution would be a char device driver which has to be
kept open as long as a reference is held.  When userspace closes it (be
that because the program has exited, been killed, etc) you can drop any
pending references.

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

* Re: [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap
  2009-05-18 13:32   ` [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap Russell King - ARM Linux
  2009-05-18 17:00     ` Kevin Hilman
@ 2009-05-18 17:08     ` Kevin Hilman
  2009-05-18 18:30       ` Russell King - ARM Linux
  2009-05-18 19:04       ` Woodruff, Richard
  1 sibling, 2 replies; 31+ messages in thread
From: Kevin Hilman @ 2009-05-18 17:08 UTC (permalink / raw)
  To: Russell King - ARM Linux, Richard Woodruff
  Cc: linux-arm-kernel, linux-omap, Jouni Hogander, Paul Walmsley

[ adding Richard W. to To: since he can probably shed some light here ]

Russell King - ARM Linux <linux@arm.linux.org.uk> writes:

> On Fri, May 15, 2009 at 11:40:41AM -0700, Kevin Hilman wrote:
>> This patch is to sync the core linux-omap PM code with mainline.  This
>> code has evolved and been used for a while the linux-omap tree, but
>> the attempt here is to finally get this into mainline.

[...]

[excerpt of sleep34xx.S]
>> +	/* IRQ mode */
>> +	bic    r0, r7, #0x1F
>> +	orr    r0, r0, #0x12
>> +	msr    cpsr, r0	/*go into IRQ mode*/
>> +	ldmia  r3!,{r4-r6}	/*load the SP and LR from SDRAM*/
>> +	mov    sp, r4	/*update the SP */
>> +	mov    lr, r5	/*update the LR */
>> +	msr    spsr, r6	/*update the SPSR */
>> +
>> +	/* ABORT mode */
>> +	bic    r0, r7, #0x1F
>> +	orr    r0, r0, #0x17
>> +	msr    cpsr, r0	/* go into ABORT mode */
>> +	ldmia  r3!,{r4-r6}	/*load the SP and LR from SDRAM */
>> +	mov    sp, r4		/*update the SP */
>> +	mov    lr, r5		/*update the LR */
>> +	msr    spsr, r6		/*update the SPSR */
>> +
>> +	/* UNDEEF mode */
>> +	bic    r0, r7, #0x1F
>> +	orr    r0, r0, #0x1B
>> +	msr    cpsr, r0		/*go into UNDEF mode */
>> +	ldmia  r3!,{r4-r6}	/*load the SP and LR from SDRAM */
>> +	mov    sp, r4		/*update the SP*/
>> +	mov    lr, r5		/*update the LR*/
>> +	msr    spsr, r6		/*update the SPSR*/
>> +
>> +	/* SYSTEM (USER) mode */
>> +	bic    r0, r7, #0x1F
>> +	orr    r0, r0, #0x1F
>> +	msr    cpsr, r0		/*go into USR mode */
>> +	ldmia  r3!,{r4-r6}	/*load the SP and LR from SDRAM*/
>> +	mov    sp, r4		/*update the SP */
>> +	mov    lr, r5		/*update the LR */
>> +	msr    spsr, r6		/*update the SPSR */
>> +	msr    cpsr, r7		/*back to original mode*/
>
> There is a function which re-initializes the abort mode registers already -
> cpu_init().  Please use that if possible instead.

Upon a quick glance, using cpu_init() would not cover all the things
that this code does.  cpu_init() only handles the init of sp for the
various modes, where this code saves/resores all the banked registers:
sp, lr and spsr as well as r8-r12 of FIQ mode.

The question in my mind however is whether the lr and spsr need to be
saved/restored?  Do we really need to preserve the context of these
handlers across idle?  Presumably we should not hit idle/suspend in
the middle of one of these handlers, so do we need to save anything
other than the stp?  Maybe Richard can shed some light here as to why
that was added.

Kevin

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

* Re: [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap
  2009-05-18 17:06       ` Russell King - ARM Linux
@ 2009-05-18 17:28         ` Kevin Hilman
  2009-05-19  5:49           ` Artem Bityutskiy
  2009-05-19 18:55         ` Kevin Hilman
  1 sibling, 1 reply; 31+ messages in thread
From: Kevin Hilman @ 2009-05-18 17:28 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Richard Woodruff, linux-arm-kernel, linux-omap, Jouni Hogander,
	Paul Walmsley

Russell King - ARM Linux <linux@arm.linux.org.uk> writes:

> On Mon, May 18, 2009 at 10:00:44AM -0700, Kevin Hilman wrote:
>> Russell King - ARM Linux <linux@arm.linux.org.uk> writes:
>> 
>> > On Fri, May 15, 2009 at 11:40:41AM -0700, Kevin Hilman wrote:
>> >> This patch is to sync the core linux-omap PM code with mainline.  This
>> >> code has evolved and been used for a while the linux-omap tree, but
>> >> the attempt here is to finally get this into mainline.
>> >> 
>> >> Following this will be a series of patches from the 'PM branch' of the
>> >> linux-omap tree to add full PM hardware support from the linux-omap
>> >> tree.
>> >> 
>> >> Much of this PM core code was written by Jouni Hogander with
>> >> significant contributions from Paul Walmsley as well as many others
>> >> from Nokia, Texas Instruments and linux-omap community.
>> >
>> > Overall comment, I think we need to rework the idle support code so
>> > that enable_hlt/disable_hlt can be used even when pm_idle has been
>> > overridden, rather than OMAP going off and inventing its own mechanisms.
>> 
>> Would adding:
>> 
>> 	if (hlt_counter)
>> 		cpu_relax();
>> 
>> to the beginning of omap*_pm_idle functions be sufficient?  That will
>> at least allow the hlt stuff to behave as expected.
>
> Yes, but the comment was also directed at the other functions which
> increment/decrement that atomic_t variable to enable/disable sleep mode.

Ah, right.  The sleep_block stuff is only used in OMAP2, we don't use
that anymore in OMAP3.  In fact, even OMAP2 users of this should be
updated to use the OMAP PM layer, so I'll just drop the sleep_block
hooks.

>> The only thing the OMAP /sys/power/sleep_while_idle hook adds to this
>> functionality is the ability to control this from sysfs.
>> 
>> Any objections to /sys/power/enable_hlt?
>
> That seems to be rather dangerous, even with your atomic based code which
> bugs if the count goes below zero.

Atomic sleep_block code to be removed.

> The problem here is that such an interface is extremely fragile.  Consider
> what happens if a program disables HLT, and then gets killed off for some
> reason.  How does this reference get balanced again?
>
> I think a better solution would be a char device driver which has to be
> kept open as long as a reference is held.  When userspace closes it (be
> that because the program has exited, been killed, etc) you can drop any
> pending references.

OK, this interface is not intended for users/applications. It is
intended only for OMAP PM developers who are developing the PM code
and want to prevent idle for various reasons during development.  It
is not intended for productions systems.

What about leaving /sys/power/sleep_while_idle but only if
CONFIG_PM_DEBUG=y?

Kevin

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

* Re: [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap
  2009-05-18 17:08     ` Kevin Hilman
@ 2009-05-18 18:30       ` Russell King - ARM Linux
  2009-05-18 19:04       ` Woodruff, Richard
  1 sibling, 0 replies; 31+ messages in thread
From: Russell King - ARM Linux @ 2009-05-18 18:30 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Richard Woodruff, linux-arm-kernel, linux-omap, Jouni Hogander,
	Paul Walmsley

On Mon, May 18, 2009 at 10:08:36AM -0700, Kevin Hilman wrote:
> [ adding Richard W. to To: since he can probably shed some light here ]
> 
> Russell King - ARM Linux <linux@arm.linux.org.uk> writes:
> 
> > On Fri, May 15, 2009 at 11:40:41AM -0700, Kevin Hilman wrote:
> >> This patch is to sync the core linux-omap PM code with mainline.  This
> >> code has evolved and been used for a while the linux-omap tree, but
> >> the attempt here is to finally get this into mainline.
> 
> [...]
> 
> Upon a quick glance, using cpu_init() would not cover all the things
> that this code does.  cpu_init() only handles the init of sp for the
> various modes, where this code saves/resores all the banked registers:
> sp, lr and spsr as well as r8-r12 of FIQ mode.

It doesn't touch sp, lr and spsr for the other modes because there's
no requirement to do so.  Think about it for a moment.

Is there any point to saving LR and SPSR for the abort, FIQ and IRQ
modes?  No - LR and SPSR are overwritten by the hardware immediately
upon entry to the relevent mode via an exception.

What about SP?  We use SP in the vector entry code, and we need to
ensure that this is re-initialized.  We never change their value, so
we know that these are constant, and therefore if we initialize them
once we can repeat the same initialization to restore their values
when those values are lost.  This is precisely what cpu_init() does.

As for FIQ r8-r12, yes this is missing, and it's something that needs
to be handled by _every_ platform which puts the CPU into low power
state, be that PXA, S3C2410, and so forth.  We have code to allow the
FIQ vector to be managed, and as yet those architectures which do
support sleep modes don't use FIQ mode, hence why there's nothing for
it yet.  Feel free to add the necessary suspend/resume code to (eg)
arch/arm/kernel/fiq.c to fill this hole though.

Lastly is system mode.  The kernel doesn't use system mode, and this
mode doesn't exist in all CPUs (its marked as unpredictable on many
older CPUs.)  We need a _generic_ extension to support that mode _if_
it is used.  Presently it is not used, and so we simply don't bother
saving those registers.

> The question in my mind however is whether the lr and spsr need to be
> saved/restored?  Do we really need to preserve the context of these
> handlers across idle?

Idle is called essentially in process context, with the exception that
it's SVC mode rather than user mode.  That means no exception handlers
will be running.

So I think you'll find cpu_init() does everything you require.

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

* RE: [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap
  2009-05-18 17:08     ` Kevin Hilman
  2009-05-18 18:30       ` Russell King - ARM Linux
@ 2009-05-18 19:04       ` Woodruff, Richard
  2009-05-18 20:24         ` Russell King - ARM Linux
  1 sibling, 1 reply; 31+ messages in thread
From: Woodruff, Richard @ 2009-05-18 19:04 UTC (permalink / raw)
  To: Kevin Hilman, Russell King - ARM Linux
  Cc: linux-arm-kernel, linux-omap, Jouni Hogander, Paul Walmsley


> From: Kevin Hilman [mailto:khilman@deeprootsystems.com]
> Sent: Monday, May 18, 2009 12:09 PM
> To: Russell King - ARM Linux; Woodruff, Richard


> > There is a function which re-initializes the abort mode registers already -
> > cpu_init().  Please use that if possible instead.
>
> Upon a quick glance, using cpu_init() would not cover all the things
> that this code does.  cpu_init() only handles the init of sp for the
> various modes, where this code saves/resores all the banked registers:
> sp, lr and spsr as well as r8-r12 of FIQ mode.

cpu_init() is not yet accessible at the point this code is running.  You could reduce the context perhaps trying to optimize to what the Linux-ARM implementation is today or do a more generic save like is there now.

This code is copied into place from the .S code into SRAM.  Its position independent and is not linked for this address.  If you want to call functions outside of it you need to manually setup linkage.

Calling outside functions on the way _DOWN_ is ok.  For instance in current TI reference code all cache flush is calling to kernel functions.  This saves in space, duplication maintenance and is actually _much_ quicker as it executes from a cached address range.  The cache flush code takes 770uS from kernel area and takes 2.2mS from sram (non-cached map).

Calling functions on the way _UP_ from wake is NOT easy (like the one you propose) as the MMU is not yet enabled.  The MMU is enabled only below this.  Calling cpu_init() is not do able here.  Even if you dress up the calling pointer to the physical address, it won't work as cpu_init() makes a global variable dereferences (smp_processor_id & stacks[]).

Regards,
Richard W.

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

* Re: [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap
  2009-05-18 19:04       ` Woodruff, Richard
@ 2009-05-18 20:24         ` Russell King - ARM Linux
  2009-05-18 20:47           ` Woodruff, Richard
  2009-05-19  0:23           ` Kevin Hilman
  0 siblings, 2 replies; 31+ messages in thread
From: Russell King - ARM Linux @ 2009-05-18 20:24 UTC (permalink / raw)
  To: Woodruff, Richard
  Cc: Kevin Hilman, linux-arm-kernel, linux-omap, Jouni Hogander,
	Paul Walmsley

On Mon, May 18, 2009 at 02:04:19PM -0500, Woodruff, Richard wrote:
> cpu_init() is not yet accessible at the point this code is running.

Not at that _exact_ point, but there's no need what so ever for it
to be at that exact point.  There's nothing stopping a call to
cpu_init() happening later.  Much later.

> You could reduce the context perhaps trying to optimize to what the
> Linux-ARM implementation is today or do a more generic save like is
> there now.
> 
> This code is copied into place from the .S code into SRAM.  Its
> position independent and is not linked for this address.  If you want
> to call functions outside of it you need to manually setup linkage.

I wouldn't want to.

> Calling functions on the way _UP_ from wake is NOT easy (like the one
> you propose) as the MMU is not yet enabled.  The MMU is enabled only
> below this.  Calling cpu_init() is not do able here.  Even if you
> dress up the calling pointer to the physical address, it won't work
> as cpu_init() makes a global variable dereferences (smp_processor_id
> & stacks[]).

As long as IRQs and FIQs are disabled, you are in a 100% predictable
environment.

1. No IRQ or FIQ will be entered; if they are the CPU is buggy.
2. No data or prefetch abort will be entered _unless_ you purposely
   access some non-present memory (and you're not exactly going to
   start paging memory in with IRQs disabled.)

So restoring the abort and IRQ mode register state is just plain not
necessary in your SRAM code.

Let's look at the code.  Here are the pertinent bits from Kevin's patch:

static void omap3_pm_idle(void)
{
        local_irq_disable();
        local_fiq_disable();

        omap_sram_idle();

        local_fiq_enable();
        local_irq_enable();
}

static void omap_sram_idle(void)
{
        _omap_sram_idle(NULL, save_state);
}

        _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
                                         omap34xx_cpu_suspend_sz);
        pm_idle = omap3_pm_idle;

_omap_sram_idle() is the assembly code we're discussing, and here we're
referring to its version in SRAM.  From the above code, we can clearly
see that this is entered with FIQs and IRQs disabled.  So everything
inside omap_sram_idle() is running in a well defined environment provided
prefetch and data aborts don't happen.

There is nothing stopping this from becoming:

static void omap3_pm_idle(void)
{
        local_irq_disable();
        local_fiq_disable();

        omap_sram_idle();
+	cpu_init();

        local_fiq_enable();
        local_irq_enable();
}

and having the saving of IRQ, FIQ and abort mode registers removed
from the SRAM code.

Other SoCs do precisely this - let's look at PXA:

        pxa_cpu_pm_fns->enter(state);
        cpu_init();

The call to the enter method essentially calls the core specific suspend
function (eg, pxa25x_cpu_suspend()), which is an assembly function which
ultimately ends up powering down the core resulting in full loss of state
in the CPU.  We seem to be able to avoid having to save the exception mode
registers there.

The same thing is done with sa11x0 and Samsung SoCs.

I don't see any reason for OMAP to be "special" in this regard.

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

* RE: [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap
  2009-05-18 20:24         ` Russell King - ARM Linux
@ 2009-05-18 20:47           ` Woodruff, Richard
  2009-05-18 21:11             ` Russell King - ARM Linux
  2009-05-19  0:23           ` Kevin Hilman
  1 sibling, 1 reply; 31+ messages in thread
From: Woodruff, Richard @ 2009-05-18 20:47 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Kevin Hilman, linux-arm-kernel, linux-omap, Jouni Hogander,
	Paul Walmsley


> From: Russell King - ARM Linux [mailto:linux@arm.linux.org.uk]
> Sent: Monday, May 18, 2009 3:25 PM

> The call to the enter method essentially calls the core specific suspend
> function (eg, pxa25x_cpu_suspend()), which is an assembly function which
> ultimately ends up powering down the core resulting in full loss of state
> in the CPU.  We seem to be able to avoid having to save the exception mode
> registers there.
>
> The same thing is done with sa11x0 and Samsung SoCs.
>
> I don't see any reason for OMAP to be "special" in this regard.

The code flow is:
        - Wakeup event
        - ARM reboots and uses SOC mask ROM context restore helper
        - Mask ROM code jump to restore pointers with MMU OFF.
        - Restore code resets ARM CortexA8 state
        -*- Trustzone SMI calls are made to restore some secure state
        - Jump back from SRAM to C code

The dangling question to me is if any of the cpu state is needed by the trustzone monitor code as a precondition.  The doc's I have led me to believe its ok, but I've not verified this.

Regards,
Richard W.


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

* Re: [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap
  2009-05-18 20:47           ` Woodruff, Richard
@ 2009-05-18 21:11             ` Russell King - ARM Linux
  2009-05-18 21:19               ` Woodruff, Richard
  0 siblings, 1 reply; 31+ messages in thread
From: Russell King - ARM Linux @ 2009-05-18 21:11 UTC (permalink / raw)
  To: Woodruff, Richard
  Cc: Kevin Hilman, linux-arm-kernel, linux-omap, Jouni Hogander,
	Paul Walmsley

On Mon, May 18, 2009 at 03:47:31PM -0500, Woodruff, Richard wrote:
> The code flow is:
>         - Wakeup event
>         - ARM reboots and uses SOC mask ROM context restore helper
>         - Mask ROM code jump to restore pointers with MMU OFF.
>         - Restore code resets ARM CortexA8 state
>         -*- Trustzone SMI calls are made to restore some secure state
>         - Jump back from SRAM to C code
> 
> The dangling question to me is if any of the cpu state is needed by
> the trustzone monitor code as a precondition.  The doc's I have led
> me to believe its ok, but I've not verified this.

There shouldn't be - it would be _really_ silly if the trustzone monitor
had pre-requisits for the exception mode registers.  There's no way that
Linux's use of the exception mode registers is anywhere near the same as
other OSes, and Linux's use of the exception mode registers has changed
over time anyway.  We make no promise that we'll keep the way we're using
these registers today either.

So there are no external guarantees about what useful state the kernel
puts into these registers.  Having external code rely on some state
there would itself be broken.

There's also the problem that if there was a dependency on the insecure
exception mode registers from within the trusted environment, that'd
surely be a rather big security problem in itself.

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

* RE: [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap
  2009-05-18 21:11             ` Russell King - ARM Linux
@ 2009-05-18 21:19               ` Woodruff, Richard
  0 siblings, 0 replies; 31+ messages in thread
From: Woodruff, Richard @ 2009-05-18 21:19 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Kevin Hilman, linux-arm-kernel, linux-omap, Jouni Hogander,
	Paul Walmsley


> From: Russell King - ARM Linux [mailto:linux@arm.linux.org.uk]
> Sent: Monday, May 18, 2009 4:11 PM

> On Mon, May 18, 2009 at 03:47:31PM -0500, Woodruff, Richard wrote:
> > The code flow is:
> >         - Wakeup event
> >         - ARM reboots and uses SOC mask ROM context restore helper
> >         - Mask ROM code jump to restore pointers with MMU OFF.
> >         - Restore code resets ARM CortexA8 state
> >         -*- Trustzone SMI calls are made to restore some secure state
> >         - Jump back from SRAM to C code
> >
> > The dangling question to me is if any of the cpu state is needed by
> > the trustzone monitor code as a precondition.  The doc's I have led
> > me to believe its ok, but I've not verified this.
>
> There shouldn't be - it would be _really_ silly if the trustzone monitor
> had pre-requisits for the exception mode registers.  There's no way that
> Linux's use of the exception mode registers is anywhere near the same as
> other OSes, and Linux's use of the exception mode registers has changed
> over time anyway.  We make no promise that we'll keep the way we're using
> these registers today either.
>
> So there are no external guarantees about what useful state the kernel
> puts into these registers.  Having external code rely on some state
> there would itself be broken.
>
> There's also the problem that if there was a dependency on the insecure
> exception mode registers from within the trusted environment, that'd
> surely be a rather big security problem in itself.

Yes those are reasonable comments.

In OMAP2 time security required nasty hacks to Linux vectors code (and other OSes).

For OMAP3 the security API does take parameters to say if local OS interrupts are allowed or not. In the case they are there the vector base in monitor is used.  Some stacking does occur to allow return.  So yes as long as local IRQs are off it should be ok.  Changes still need validation.

Security does something to SOC resources like DMA which have caused confusion.  For instance you call the API and specify a DMA channel.  This is ok.  But you will find some status left in channel which needs clean up before a successful sleep can happen.


Regards,
Richard W.


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

* Re: [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap
  2009-05-18 20:24         ` Russell King - ARM Linux
  2009-05-18 20:47           ` Woodruff, Richard
@ 2009-05-19  0:23           ` Kevin Hilman
  1 sibling, 0 replies; 31+ messages in thread
From: Kevin Hilman @ 2009-05-19  0:23 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Woodruff, Richard, linux-arm-kernel, linux-omap, Jouni Hogander,
	Paul Walmsley

Russell King - ARM Linux <linux@arm.linux.org.uk> writes:

> On Mon, May 18, 2009 at 02:04:19PM -0500, Woodruff, Richard wrote:
>> cpu_init() is not yet accessible at the point this code is running.
>
> Not at that _exact_ point, but there's no need what so ever for it
> to be at that exact point.  There's nothing stopping a call to
> cpu_init() happening later.  Much later.
>
>> You could reduce the context perhaps trying to optimize to what the
>> Linux-ARM implementation is today or do a more generic save like is
>> there now.
>> 
>> This code is copied into place from the .S code into SRAM.  Its
>> position independent and is not linked for this address.  If you want
>> to call functions outside of it you need to manually setup linkage.
>
> I wouldn't want to.
>
>> Calling functions on the way _UP_ from wake is NOT easy (like the one
>> you propose) as the MMU is not yet enabled.  The MMU is enabled only
>> below this.  Calling cpu_init() is not do able here.  Even if you
>> dress up the calling pointer to the physical address, it won't work
>> as cpu_init() makes a global variable dereferences (smp_processor_id
>> & stacks[]).
>
> As long as IRQs and FIQs are disabled, you are in a 100% predictable
> environment.
>
> 1. No IRQ or FIQ will be entered; if they are the CPU is buggy.
> 2. No data or prefetch abort will be entered _unless_ you purposely
>    access some non-present memory (and you're not exactly going to
>    start paging memory in with IRQs disabled.)
>
> So restoring the abort and IRQ mode register state is just plain not
> necessary in your SRAM code.
>
> Let's look at the code.  Here are the pertinent bits from Kevin's patch:
>
> static void omap3_pm_idle(void)
> {
>         local_irq_disable();
>         local_fiq_disable();
>
>         omap_sram_idle();
>
>         local_fiq_enable();
>         local_irq_enable();
> }
>
> static void omap_sram_idle(void)
> {
>         _omap_sram_idle(NULL, save_state);
> }
>
>         _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
>                                          omap34xx_cpu_suspend_sz);
>         pm_idle = omap3_pm_idle;
>
> _omap_sram_idle() is the assembly code we're discussing, and here we're
> referring to its version in SRAM.  From the above code, we can clearly
> see that this is entered with FIQs and IRQs disabled.  So everything
> inside omap_sram_idle() is running in a well defined environment provided
> prefetch and data aborts don't happen.
>
> There is nothing stopping this from becoming:
>
> static void omap3_pm_idle(void)
> {
>         local_irq_disable();
>         local_fiq_disable();
>
>         omap_sram_idle();
> +	cpu_init();
>
>         local_fiq_enable();
>         local_irq_enable();
> }
>
> and having the saving of IRQ, FIQ and abort mode registers removed
> from the SRAM code.

I did some quick experiments on a kernel that includes full OFF-mode
support and this and this is working fine.

For it to work for both idle and suspend, I put the cpu_init()
immediately after the return from SRAM (IOW, right after the call to
_omap_sram_idle() inside omap_sram_idle()).

Now I can totally drop all the sp/lr/spsr save/restore code from the
asm code. Nice!

> Other SoCs do precisely this - let's look at PXA:
>
>         pxa_cpu_pm_fns->enter(state);
>         cpu_init();
>
> The call to the enter method essentially calls the core specific suspend
> function (eg, pxa25x_cpu_suspend()), which is an assembly function which
> ultimately ends up powering down the core resulting in full loss of state
> in the CPU.  We seem to be able to avoid having to save the exception mode
> registers there.
>
> The same thing is done with sa11x0 and Samsung SoCs.
>
> I don't see any reason for OMAP to be "special" in this regard.

Neither do I.  Thanks for the review and the suggestion.

Kevin

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

* Re: [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap
  2009-05-18 17:28         ` Kevin Hilman
@ 2009-05-19  5:49           ` Artem Bityutskiy
  2009-05-19 14:57             ` Kevin Hilman
  0 siblings, 1 reply; 31+ messages in thread
From: Artem Bityutskiy @ 2009-05-19  5:49 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Russell King - ARM Linux, Richard Woodruff, linux-arm-kernel,
	linux-omap, Jouni Hogander, Paul Walmsley

Kevin Hilman wrote:
>> The problem here is that such an interface is extremely fragile.  Consider
>> what happens if a program disables HLT, and then gets killed off for some
>> reason.  How does this reference get balanced again?
>>
>> I think a better solution would be a char device driver which has to be
>> kept open as long as a reference is held.  When userspace closes it (be
>> that because the program has exited, been killed, etc) you can drop any
>> pending references.
> 
> OK, this interface is not intended for users/applications. It is
> intended only for OMAP PM developers who are developing the PM code
> and want to prevent idle for various reasons during development.  It
> is not intended for productions systems.
> 
> What about leaving /sys/power/sleep_while_idle but only if
> CONFIG_PM_DEBUG=y?

Sounds like debugfs is the good place for this then.

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)
--
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] 31+ messages in thread

* Re: [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap
  2009-05-19  5:49           ` Artem Bityutskiy
@ 2009-05-19 14:57             ` Kevin Hilman
  0 siblings, 0 replies; 31+ messages in thread
From: Kevin Hilman @ 2009-05-19 14:57 UTC (permalink / raw)
  To: Artem.Bityutskiy
  Cc: Russell King - ARM Linux, Richard Woodruff, linux-arm-kernel,
	linux-omap, Jouni Hogander, Paul Walmsley

Artem Bityutskiy <Artem.Bityutskiy@nokia.com> writes:

> Kevin Hilman wrote:
>>> The problem here is that such an interface is extremely fragile.  Consider
>>> what happens if a program disables HLT, and then gets killed off for some
>>> reason.  How does this reference get balanced again?
>>>
>>> I think a better solution would be a char device driver which has to be
>>> kept open as long as a reference is held.  When userspace closes it (be
>>> that because the program has exited, been killed, etc) you can drop any
>>> pending references.
>>
>> OK, this interface is not intended for users/applications. It is
>> intended only for OMAP PM developers who are developing the PM code
>> and want to prevent idle for various reasons during development.  It
>> is not intended for productions systems.
>>
>> What about leaving /sys/power/sleep_while_idle but only if
>> CONFIG_PM_DEBUG=y?
>
> Sounds like debugfs is the good place for this then.
>

Sound OK to me.

Kevin

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

* Re: [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap
  2009-05-18 17:06       ` Russell King - ARM Linux
  2009-05-18 17:28         ` Kevin Hilman
@ 2009-05-19 18:55         ` Kevin Hilman
  2009-05-28 13:43           ` Russell King - ARM Linux
  1 sibling, 1 reply; 31+ messages in thread
From: Kevin Hilman @ 2009-05-19 18:55 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linux-arm-kernel, linux-omap, Jouni Hogander, Paul Walmsley

Russell King - ARM Linux <linux@arm.linux.org.uk> writes:

> On Mon, May 18, 2009 at 10:00:44AM -0700, Kevin Hilman wrote:
>> Russell King - ARM Linux <linux@arm.linux.org.uk> writes:
>> 
>> > On Fri, May 15, 2009 at 11:40:41AM -0700, Kevin Hilman wrote:
>> >> This patch is to sync the core linux-omap PM code with mainline.  This
>> >> code has evolved and been used for a while the linux-omap tree, but
>> >> the attempt here is to finally get this into mainline.
>> >> 
>> >> Following this will be a series of patches from the 'PM branch' of the
>> >> linux-omap tree to add full PM hardware support from the linux-omap
>> >> tree.
>> >> 
>> >> Much of this PM core code was written by Jouni Hogander with
>> >> significant contributions from Paul Walmsley as well as many others
>> >> from Nokia, Texas Instruments and linux-omap community.
>> >
>> > Overall comment, I think we need to rework the idle support code so
>> > that enable_hlt/disable_hlt can be used even when pm_idle has been
>> > overridden, rather than OMAP going off and inventing its own mechanisms.
>> 
>> Would adding:
>> 
>> 	if (hlt_counter)
>> 		cpu_relax();
>> 
>> to the beginning of omap*_pm_idle functions be sufficient?  That will
>> at least allow the hlt stuff to behave as expected.
>
> Yes, but the comment was also directed at the other functions which
> increment/decrement that atomic_t variable to enable/disable sleep mode.
>

Russell,

Do you have a preference in how to export the hlt_counter to
platform-specific code?

The patch below creates a can_hlt() function that can be called from
platform-specific idle code.

Kevin

>From 23c802a0a1e9bb24ca51af9cf18b972590f8d1dc Mon Sep 17 00:00:00 2001
From: Kevin Hilman <khilman@deeprootsystems.com>
Date: Tue, 19 May 2009 11:34:12 -0700
Subject: [PATCH] ARM: add can_hlt() for platform PM code to check before idling

When platform-specific code overrides pm_idle, the hlt_counter
is no longer used.  Create a can_hlt() check which returns
the hlt_counter so platform code can check it and thus
honor the requests of enable_hlt()/disable_hlt() users.

Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
 arch/arm/include/asm/system.h |    1 +
 arch/arm/kernel/process.c     |    7 +++++++
 2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index bd4dc8e..ff9e2dd 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -313,6 +313,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
 
 extern void disable_hlt(void);
 extern void enable_hlt(void);
+extern int can_hlt(void);
 
 #include <asm-generic/cmpxchg-local.h>
 
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index c3265a2..1b414b8 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -68,6 +68,13 @@ void enable_hlt(void)
 
 EXPORT_SYMBOL(enable_hlt);
 
+int can_hlt(void)
+{
+	return !hlt_counter;
+}
+
+EXPORT_SYMBOL(can_hlt);
+
 static int __init nohlt_setup(char *__unused)
 {
 	hlt_counter = 1;
-- 
1.6.2.2


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

* Re: [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap
  2009-05-19 18:55         ` Kevin Hilman
@ 2009-05-28 13:43           ` Russell King - ARM Linux
  0 siblings, 0 replies; 31+ messages in thread
From: Russell King - ARM Linux @ 2009-05-28 13:43 UTC (permalink / raw)
  To: Kevin Hilman; +Cc: linux-arm-kernel, linux-omap, Jouni Hogander, Paul Walmsley

On Tue, May 19, 2009 at 11:55:41AM -0700, Kevin Hilman wrote:
> Russell King - ARM Linux <linux@arm.linux.org.uk> writes:
> 
> > On Mon, May 18, 2009 at 10:00:44AM -0700, Kevin Hilman wrote:
> >> Russell King - ARM Linux <linux@arm.linux.org.uk> writes:
> >> 
> >> > On Fri, May 15, 2009 at 11:40:41AM -0700, Kevin Hilman wrote:
> >> >> This patch is to sync the core linux-omap PM code with mainline.  This
> >> >> code has evolved and been used for a while the linux-omap tree, but
> >> >> the attempt here is to finally get this into mainline.
> >> >> 
> >> >> Following this will be a series of patches from the 'PM branch' of the
> >> >> linux-omap tree to add full PM hardware support from the linux-omap
> >> >> tree.
> >> >> 
> >> >> Much of this PM core code was written by Jouni Hogander with
> >> >> significant contributions from Paul Walmsley as well as many others
> >> >> from Nokia, Texas Instruments and linux-omap community.
> >> >
> >> > Overall comment, I think we need to rework the idle support code so
> >> > that enable_hlt/disable_hlt can be used even when pm_idle has been
> >> > overridden, rather than OMAP going off and inventing its own mechanisms.
> >> 
> >> Would adding:
> >> 
> >> 	if (hlt_counter)
> >> 		cpu_relax();
> >> 
> >> to the beginning of omap*_pm_idle functions be sufficient?  That will
> >> at least allow the hlt stuff to behave as expected.
> >
> > Yes, but the comment was also directed at the other functions which
> > increment/decrement that atomic_t variable to enable/disable sleep mode.
> >
> 
> Russell,
> 
> Do you have a preference in how to export the hlt_counter to
> platform-specific code?

Sorry, I haven't had time to look at this, and the work I did to change
the idle loop got lost when I last re-built my git tree.

But... your patch isn't what I was meaning.  I was meaning to avoid
calling the idle function (_any_ idle function) if hlt_counter was
non-zero.

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

end of thread, other threads:[~2009-05-28 13:43 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-05-15 18:40 [PATCH 00/11] OMAP2/3: PM sync-up Kevin Hilman
2009-05-15 18:40 ` [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap Kevin Hilman
2009-05-15 18:40   ` [PATCH 02/11] OMAP: Add new function to check wether there is irq pending Kevin Hilman
2009-05-15 18:40     ` [PATCH 03/11] OMAP3: PM: Force IVA2 into idle during bootup Kevin Hilman
2009-05-15 18:40       ` [PATCH 04/11] OMAP3: PM: Add wake-up bit defintiions for CONTROL_PADCONF_X Kevin Hilman
2009-05-15 18:40         ` [PATCH 05/11] OMAP3: PM: UART: disable clocks when idle and off-mode support Kevin Hilman
2009-05-15 18:40           ` [PATCH 06/11] OMAP3: PM: Add D2D clocks and auto-idle setup to PRCM init Kevin Hilman
2009-05-15 18:40             ` [PATCH 07/11] OMAP3: PM: D2D clockdomain supports SW supervised transitions Kevin Hilman
2009-05-15 18:40               ` [PATCH 08/11] OMAP3: PM: Ensure MUSB block can idle when driver not loaded Kevin Hilman
2009-05-15 18:40                 ` [PATCH 09/11] OMAP3: PM: Ensure PRCM interrupts are cleared at boot Kevin Hilman
2009-05-15 18:40                   ` [PATCH 10/11] OMAP3: PM: Clear pending PRCM reset flags on init Kevin Hilman
2009-05-15 18:40                     ` [PATCH 11/11] OMAP3: PM: prevent module wakeups from waking IVA2 Kevin Hilman
2009-05-18 13:16                 ` [PATCH 08/11] OMAP3: PM: Ensure MUSB block can idle when driver not loaded Russell King - ARM Linux
2009-05-18 14:50                   ` Kevin Hilman
2009-05-18 15:04                     ` Tony Lindgren
2009-05-18 13:32   ` [PATCH 01/11] OMAP2/3: PM: push core PM code from linux-omap Russell King - ARM Linux
2009-05-18 17:00     ` Kevin Hilman
2009-05-18 17:06       ` Russell King - ARM Linux
2009-05-18 17:28         ` Kevin Hilman
2009-05-19  5:49           ` Artem Bityutskiy
2009-05-19 14:57             ` Kevin Hilman
2009-05-19 18:55         ` Kevin Hilman
2009-05-28 13:43           ` Russell King - ARM Linux
2009-05-18 17:08     ` Kevin Hilman
2009-05-18 18:30       ` Russell King - ARM Linux
2009-05-18 19:04       ` Woodruff, Richard
2009-05-18 20:24         ` Russell King - ARM Linux
2009-05-18 20:47           ` Woodruff, Richard
2009-05-18 21:11             ` Russell King - ARM Linux
2009-05-18 21:19               ` Woodruff, Richard
2009-05-19  0:23           ` 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.