[ARM] 4488/1: pxa: move pxa25x/pxa27x specific code out of pm.c
authorEric Miao <eric.y.miao@gmail.com>
Wed, 18 Jul 2007 10:38:45 +0000 (11:38 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Fri, 20 Jul 2007 16:25:10 +0000 (17:25 +0100)
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
arch/arm/mach-pxa/pxa25x.c
arch/arm/mach-pxa/pxa27x.c
include/asm-arm/arch-pxa/pm.h

index e66dbc2..b59a81a 100644 (file)
 #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);
index 9d9422e..1ec4bf1 100644 (file)
@@ -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));
index c85f0b0..9240d37 100644 (file)
@@ -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));
        }
index 52243a6..62b6900 100644 (file)
@@ -7,5 +7,14 @@
  *
  */
 
-extern int pxa_pm_prepare(suspend_state_t state);
+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);
+};
+
+extern struct pxa_cpu_pm_fns *pxa_cpu_pm_fns;
+
 extern int pxa_pm_enter(suspend_state_t state);