From 711be5ccfe9a02ba560aa918a008c31ea4760163 Mon Sep 17 00:00:00 2001
From: Eric Miao <eric.y.miao@gmail.com>
Date: Wed, 18 Jul 2007 11:38:45 +0100
Subject: [ARM] 4488/1: pxa: move pxa25x/pxa27x specific code out of pm.c

1. introduce a structure pxa_cpu_pm_fns for pxa25x/pxa27x specific
   operations as follows:

	struct pxa_cpu_pm_fns {
		int	save_size;
		void	(*save)(unsigned long *);
		void	(*restore)(unsigned long *);
		int	(*valid)(suspend_state_t state);
		void	(*enter)(suspend_state_t state);
	}

2. processor specific registers saving and restoring are performed
   by calling the corresponding (*save) and (*restore)

3. pxa_cpu_pm_fns->save_size should be initialized to the required
   size for processor specific registers saving, the allocated
   memory address will be passed to (*save) and (*restore)

   memory allocation happens early in pxa_pm_init(), and save_size
   should be assigned prior to this (which is usually true, since
   pxa_pm_init() happens in device_initcall()

4. there're some redundancies for those SLEEP_SAVE_XXX and related
   macros, will be fixed later, one way possible is for the system
   devices to handle the specific registers saving and restoring

Signed-off-by: eric miao <eric.y.miao@gmail.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-pxa/pm.c     | 169 ++++++++++++---------------------------------
 arch/arm/mach-pxa/pxa25x.c |  84 ++++++++++++++++++++--
 arch/arm/mach-pxa/pxa27x.c | 117 +++++++++++++++++++++++++++++--
 3 files changed, 234 insertions(+), 136 deletions(-)

(limited to 'arch')

diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c
index e66dbc26add1..b59a81a8e7d3 100644
--- a/arch/arm/mach-pxa/pm.c
+++ b/arch/arm/mach-pxa/pm.c
@@ -24,61 +24,13 @@
 #include <asm/arch/lubbock.h>
 #include <asm/mach/time.h>
 
-
-/*
- * Debug macros
- */
-#undef DEBUG
-
-#define SAVE(x)		sleep_save[SLEEP_SAVE_##x] = x
-#define RESTORE(x)	x = sleep_save[SLEEP_SAVE_##x]
-
-#define RESTORE_GPLEVEL(n) do { \
-	GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \
-	GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \
-} while (0)
-
-/*
- * List of global PXA peripheral registers to preserve.
- * More ones like CP and general purpose register values are preserved
- * with the stack pointer in sleep.S.
- */
-enum {	SLEEP_SAVE_START = 0,
-
-	SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, SLEEP_SAVE_GPLR3,
-	SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, SLEEP_SAVE_GPDR3,
-	SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, SLEEP_SAVE_GRER3,
-	SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, SLEEP_SAVE_GFER3,
-	SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3,
-
-	SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
-	SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U,
-	SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U,
-	SLEEP_SAVE_GAFR3_L, SLEEP_SAVE_GAFR3_U,
-
-	SLEEP_SAVE_PSTR,
-
-	SLEEP_SAVE_ICMR,
-	SLEEP_SAVE_CKEN,
-
-#ifdef CONFIG_PXA27x
- 	SLEEP_SAVE_MDREFR,
- 	SLEEP_SAVE_PWER, SLEEP_SAVE_PCFR, SLEEP_SAVE_PRER,
- 	SLEEP_SAVE_PFER, SLEEP_SAVE_PKWR,
-#endif
-
-	SLEEP_SAVE_CKSUM,
-
-	SLEEP_SAVE_SIZE
-};
-
+struct pxa_cpu_pm_fns *pxa_cpu_pm_fns;
+static unsigned long *sleep_save;
 
 int pxa_pm_enter(suspend_state_t state)
 {
-	unsigned long sleep_save[SLEEP_SAVE_SIZE];
-	unsigned long checksum = 0;
+	unsigned long sleep_save_checksum = 0, checksum = 0;
 	int i;
-	extern void pxa_cpu_pm_enter(suspend_state_t state);
 
 #ifdef CONFIG_IWMMXT
 	/* force any iWMMXt context to ram **/
@@ -86,100 +38,35 @@ int pxa_pm_enter(suspend_state_t state)
 		iwmmxt_task_disable(NULL);
 #endif
 
-	SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2);
-	SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2);
-	SAVE(GRER0); SAVE(GRER1); SAVE(GRER2);
-	SAVE(GFER0); SAVE(GFER1); SAVE(GFER2);
-	SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2);
-
-	SAVE(GAFR0_L); SAVE(GAFR0_U);
-	SAVE(GAFR1_L); SAVE(GAFR1_U);
-	SAVE(GAFR2_L); SAVE(GAFR2_U);
-
-#ifdef CONFIG_PXA27x
-	SAVE(MDREFR);
-	SAVE(GPLR3); SAVE(GPDR3); SAVE(GRER3); SAVE(GFER3); SAVE(PGSR3);
-	SAVE(GAFR3_L); SAVE(GAFR3_U);
-	SAVE(PWER); SAVE(PCFR); SAVE(PRER);
-	SAVE(PFER); SAVE(PKWR);
-#endif
-
-	SAVE(ICMR);
-	ICMR = 0;
-
-	SAVE(CKEN);
-	SAVE(PSTR);
-
-	/* Note: wake up source are set up in each machine specific files */
-
-	/* clear GPIO transition detect  bits */
-	GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2;
-#ifdef CONFIG_PXA27x
-	GEDR3 = GEDR3;
-#endif
+	pxa_cpu_pm_fns->save(sleep_save);
 
 	/* Clear sleep reset status */
 	RCSR = RCSR_SMR;
 
 	/* before sleeping, calculate and save a checksum */
-	for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
-		checksum += sleep_save[i];
-	sleep_save[SLEEP_SAVE_CKSUM] = checksum;
+	for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++)
+		sleep_save_checksum += sleep_save[i];
 
 	/* *** go zzz *** */
-	pxa_cpu_pm_enter(state);
-
+	pxa_cpu_pm_fns->enter(state);
 	cpu_init();
 
 	/* after sleeping, validate the checksum */
-	checksum = 0;
-	for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
+	for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++)
 		checksum += sleep_save[i];
 
 	/* if invalid, display message and wait for a hardware reset */
-	if (checksum != sleep_save[SLEEP_SAVE_CKSUM]) {
+	if (checksum != sleep_save_checksum) {
 #ifdef CONFIG_ARCH_LUBBOCK
 		LUB_HEXLED = 0xbadbadc5;
 #endif
 		while (1)
-			pxa_cpu_pm_enter(state);
+			pxa_cpu_pm_fns->enter(state);
 	}
 
-	/* ensure not to come back here if it wasn't intended */
-	PSPR = 0;
-
-	/* restore registers */
-	RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2);
-	RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2);
-	RESTORE(GAFR0_L); RESTORE(GAFR0_U);
-	RESTORE(GAFR1_L); RESTORE(GAFR1_U);
-	RESTORE(GAFR2_L); RESTORE(GAFR2_U);
-	RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2);
-	RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2);
-	RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2);
-
-#ifdef CONFIG_PXA27x
-	RESTORE(MDREFR);
-	RESTORE_GPLEVEL(3); RESTORE(GPDR3);
-	RESTORE(GAFR3_L); RESTORE(GAFR3_U);
-	RESTORE(GRER3); RESTORE(GFER3); RESTORE(PGSR3);
-	RESTORE(PWER); RESTORE(PCFR); RESTORE(PRER);
-	RESTORE(PFER); RESTORE(PKWR);
-#endif
-
-	PSSR = PSSR_RDH | PSSR_PH;
-
-	RESTORE(CKEN);
-
-	ICLR = 0;
-	ICCR = 1;
-	RESTORE(ICMR);
+	pxa_cpu_pm_fns->restore(sleep_save);
 
-	RESTORE(PSTR);
-
-#ifdef DEBUG
-	printk(KERN_DEBUG "*** made it back from resume\n");
-#endif
+	pr_debug("*** made it back from resume\n");
 
 	return 0;
 }
@@ -190,3 +77,35 @@ unsigned long sleep_phys_sp(void *sp)
 {
 	return virt_to_phys(sp);
 }
+
+static int pxa_pm_valid(suspend_state_t state)
+{
+	if (pxa_cpu_pm_fns)
+		return pxa_cpu_pm_fns->valid(state);
+
+	return -EINVAL;
+}
+
+static struct pm_ops pxa_pm_ops = {
+	.valid		= pxa_pm_valid,
+	.enter		= pxa_pm_enter,
+};
+
+static int __init pxa_pm_init(void)
+{
+	if (!pxa_cpu_pm_fns) {
+		printk(KERN_ERR "no valid pxa_cpu_pm_fns defined\n");
+		return -EINVAL;
+	}
+
+	sleep_save = kmalloc(pxa_cpu_pm_fns->save_size, GFP_KERNEL);
+	if (!sleep_save) {
+		printk(KERN_ERR "failed to alloc memory for pm save\n");
+		return -ENOMEM;
+	}
+
+	pm_set_ops(&pxa_pm_ops);
+	return 0;
+}
+
+device_initcall(pxa_pm_init);
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
index 9d9422e2f75c..1ec4bf1ff249 100644
--- a/arch/arm/mach-pxa/pxa25x.c
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -110,7 +110,75 @@ EXPORT_SYMBOL(get_lcdclk_frequency_10khz);
 
 #ifdef CONFIG_PM
 
-void pxa_cpu_pm_enter(suspend_state_t state)
+#define SAVE(x)		sleep_save[SLEEP_SAVE_##x] = x
+#define RESTORE(x)	x = sleep_save[SLEEP_SAVE_##x]
+
+#define RESTORE_GPLEVEL(n) do { \
+	GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \
+	GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \
+} while (0)
+
+/*
+ * List of global PXA peripheral registers to preserve.
+ * More ones like CP and general purpose register values are preserved
+ * with the stack pointer in sleep.S.
+ */
+enum {	SLEEP_SAVE_START = 0,
+
+	SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2,
+	SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2,
+	SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2,
+	SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2,
+	SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2,
+
+	SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
+	SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U,
+	SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U,
+
+	SLEEP_SAVE_PSTR,
+
+	SLEEP_SAVE_ICMR,
+	SLEEP_SAVE_CKEN,
+
+	SLEEP_SAVE_SIZE
+};
+
+
+static void pxa25x_cpu_pm_save(unsigned long *sleep_save)
+{
+	SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2);
+	SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2);
+	SAVE(GRER0); SAVE(GRER1); SAVE(GRER2);
+	SAVE(GFER0); SAVE(GFER1); SAVE(GFER2);
+	SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2);
+
+	SAVE(GAFR0_L); SAVE(GAFR0_U);
+	SAVE(GAFR1_L); SAVE(GAFR1_U);
+	SAVE(GAFR2_L); SAVE(GAFR2_U);
+
+	SAVE(ICMR);
+	SAVE(CKEN);
+	SAVE(PSTR);
+}
+
+static void pxa25x_cpu_pm_restore(unsigned long *sleep_save)
+{
+	/* restore registers */
+	RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2);
+	RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2);
+	RESTORE(GAFR0_L); RESTORE(GAFR0_U);
+	RESTORE(GAFR1_L); RESTORE(GAFR1_U);
+	RESTORE(GAFR2_L); RESTORE(GAFR2_U);
+	RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2);
+	RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2);
+	RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2);
+
+	RESTORE(CKEN);
+	RESTORE(ICMR);
+	RESTORE(PSTR);
+}
+
+static void pxa25x_cpu_pm_enter(suspend_state_t state)
 {
 	extern void pxa_cpu_suspend(unsigned int);
 	extern void pxa_cpu_resume(void);
@@ -126,10 +194,18 @@ void pxa_cpu_pm_enter(suspend_state_t state)
 	}
 }
 
-static struct pm_ops pxa25x_pm_ops = {
-	.enter		= pxa_pm_enter,
+static struct pxa_cpu_pm_fns pxa25x_cpu_pm_fns = {
+	.save_size	= SLEEP_SAVE_SIZE,
 	.valid		= pm_valid_only_mem,
+	.save		= pxa25x_cpu_pm_save,
+	.restore	= pxa25x_cpu_pm_restore,
+	.enter		= pxa25x_cpu_pm_enter,
 };
+
+static void __init pxa25x_init_pm(void)
+{
+	pxa_cpu_pm_fns = &pxa25x_cpu_pm_fns;
+}
 #endif
 
 void __init pxa25x_init_irq(void)
@@ -159,7 +235,7 @@ static int __init pxa25x_init(void)
 		if ((ret = pxa_init_dma(16)))
 			return ret;
 #ifdef CONFIG_PM
-		pm_set_ops(&pxa25x_pm_ops);
+		pxa25x_init_pm();
 #endif
 		ret = platform_add_devices(pxa25x_devices,
 					   ARRAY_SIZE(pxa25x_devices));
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index c85f0b01c326..9240d37e23fa 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -126,14 +126,109 @@ EXPORT_SYMBOL(get_lcdclk_frequency_10khz);
 
 #ifdef CONFIG_PM
 
-void pxa_cpu_pm_enter(suspend_state_t state)
+#define SAVE(x)		sleep_save[SLEEP_SAVE_##x] = x
+#define RESTORE(x)	x = sleep_save[SLEEP_SAVE_##x]
+
+#define RESTORE_GPLEVEL(n) do { \
+	GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \
+	GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \
+} while (0)
+
+/*
+ * List of global PXA peripheral registers to preserve.
+ * More ones like CP and general purpose register values are preserved
+ * with the stack pointer in sleep.S.
+ */
+enum {	SLEEP_SAVE_START = 0,
+
+	SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, SLEEP_SAVE_GPLR3,
+	SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, SLEEP_SAVE_GPDR3,
+	SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, SLEEP_SAVE_GRER3,
+	SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, SLEEP_SAVE_GFER3,
+	SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3,
+
+	SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
+	SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U,
+	SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U,
+	SLEEP_SAVE_GAFR3_L, SLEEP_SAVE_GAFR3_U,
+
+	SLEEP_SAVE_PSTR,
+
+	SLEEP_SAVE_ICMR,
+	SLEEP_SAVE_CKEN,
+
+	SLEEP_SAVE_MDREFR,
+	SLEEP_SAVE_PWER, SLEEP_SAVE_PCFR, SLEEP_SAVE_PRER,
+	SLEEP_SAVE_PFER, SLEEP_SAVE_PKWR,
+
+	SLEEP_SAVE_SIZE
+};
+
+void pxa27x_cpu_pm_save(unsigned long *sleep_save)
+{
+	SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2); SAVE(GPLR3);
+	SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2); SAVE(GPDR3);
+	SAVE(GRER0); SAVE(GRER1); SAVE(GRER2); SAVE(GRER3);
+	SAVE(GFER0); SAVE(GFER1); SAVE(GFER2); SAVE(GFER3);
+	SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2); SAVE(PGSR3);
+
+	SAVE(GAFR0_L); SAVE(GAFR0_U);
+	SAVE(GAFR1_L); SAVE(GAFR1_U);
+	SAVE(GAFR2_L); SAVE(GAFR2_U);
+	SAVE(GAFR3_L); SAVE(GAFR3_U);
+
+	SAVE(MDREFR);
+	SAVE(PWER); SAVE(PCFR); SAVE(PRER);
+	SAVE(PFER); SAVE(PKWR);
+
+	SAVE(ICMR); ICMR = 0;
+	SAVE(CKEN);
+	SAVE(PSTR);
+
+	/* Clear GPIO transition detect bits */
+	GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2; GEDR3 = GEDR3;
+}
+
+void pxa27x_cpu_pm_restore(unsigned long *sleep_save)
+{
+	/* ensure not to come back here if it wasn't intended */
+	PSPR = 0;
+
+	/* restore registers */
+	RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1);
+	RESTORE_GPLEVEL(2); RESTORE_GPLEVEL(3);
+	RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2); RESTORE(GPDR3);
+	RESTORE(GAFR0_L); RESTORE(GAFR0_U);
+	RESTORE(GAFR1_L); RESTORE(GAFR1_U);
+	RESTORE(GAFR2_L); RESTORE(GAFR2_U);
+	RESTORE(GAFR3_L); RESTORE(GAFR3_U);
+	RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2); RESTORE(GRER3);
+	RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); RESTORE(GFER3);
+	RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2); RESTORE(PGSR3);
+
+	RESTORE(MDREFR);
+	RESTORE(PWER); RESTORE(PCFR); RESTORE(PRER);
+	RESTORE(PFER); RESTORE(PKWR);
+
+	PSSR = PSSR_RDH | PSSR_PH;
+
+	RESTORE(CKEN);
+
+	ICLR = 0;
+	ICCR = 1;
+	RESTORE(ICMR);
+	RESTORE(PSTR);
+}
+
+void pxa27x_cpu_pm_enter(suspend_state_t state)
 {
 	extern void pxa_cpu_standby(void);
 	extern void pxa_cpu_suspend(unsigned int);
 	extern void pxa_cpu_resume(void);
 
 	if (state == PM_SUSPEND_STANDBY)
-		CKEN = (1 << CKEN_MEMC) | (1 << CKEN_OSTIMER) | (1 << CKEN_LCD) | (1 << CKEN_PWM0);
+		CKEN = (1 << CKEN_MEMC) | (1 << CKEN_OSTIMER) |
+			(1 << CKEN_LCD) | (1 << CKEN_PWM0);
 	else
 		CKEN = (1 << CKEN_MEMC) | (1 << CKEN_OSTIMER);
 
@@ -155,15 +250,23 @@ void pxa_cpu_pm_enter(suspend_state_t state)
 	}
 }
 
-static int pxa27x_pm_valid(suspend_state_t state)
+static int pxa27x_cpu_pm_valid(suspend_state_t state)
 {
 	return state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY;
 }
 
-static struct pm_ops pxa27x_pm_ops = {
-	.enter		= pxa_pm_enter,
-	.valid		= pxa27x_pm_valid,
+static struct pxa_cpu_pm_fns pxa27x_cpu_pm_fns = {
+	.save_size	= SLEEP_SAVE_SIZE,
+	.save		= pxa27x_cpu_pm_save,
+	.restore	= pxa27x_cpu_pm_restore,
+	.valid		= pxa27x_cpu_pm_valid,
+	.enter		= pxa27x_cpu_pm_enter,
 };
+
+static void __init pxa27x_init_pm(void)
+{
+	pxa_cpu_pm_fns = &pxa27x_cpu_pm_fns;
+}
 #endif
 
 /*
@@ -249,7 +352,7 @@ static int __init pxa27x_init(void)
 		if ((ret = pxa_init_dma(32)))
 			return ret;
 #ifdef CONFIG_PM
-		pm_set_ops(&pxa27x_pm_ops);
+		pxa27x_init_pm();
 #endif
 		ret = platform_add_devices(devices, ARRAY_SIZE(devices));
 	}
-- 
cgit v1.2.2