X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Farm%2Fmach-pxa%2Fpm.c;h=b4d8276d6050b1e34d16c06153228f03c0b113a3;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=b1103400b8e77462b9dd97966af086ac0cb92b83;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c index b1103400b..b4d8276d6 100644 --- a/arch/arm/mach-pxa/pm.c +++ b/arch/arm/mach-pxa/pm.c @@ -10,8 +10,8 @@ * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License. */ -#include #include +#include #include #include #include @@ -19,6 +19,10 @@ #include #include #include +#include +#include +#include +#include /* @@ -26,12 +30,14 @@ */ #undef DEBUG -extern void pxa_cpu_suspend(void); -extern void pxa_cpu_resume(void); - #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 @@ -39,95 +45,97 @@ extern void pxa_cpu_resume(void); */ enum { SLEEP_SAVE_START = 0, - SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER, - SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3, + 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_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_GAFR0_L, SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR2_L, - SLEEP_SAVE_GAFR0_U, SLEEP_SAVE_GAFR1_U, SLEEP_SAVE_GAFR2_U, + 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_FFIER, SLEEP_SAVE_FFLCR, SLEEP_SAVE_FFMCR, - SLEEP_SAVE_FFSPR, SLEEP_SAVE_FFISR, - SLEEP_SAVE_FFDLL, SLEEP_SAVE_FFDLH, + 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 }; -static int pxa_pm_enter(u32 state) +int pxa_pm_enter(suspend_state_t state) { unsigned long sleep_save[SLEEP_SAVE_SIZE]; unsigned long checksum = 0; - unsigned long delta; + struct timespec delta, rtc; int i; + extern void pxa_cpu_pm_enter(suspend_state_t state); - if (state != PM_SUSPEND_MEM) - return -EINVAL; +#ifdef CONFIG_IWMMXT + /* force any iWMMXt context to ram **/ + if (elf_hwcap & HWCAP_IWMMXT) + iwmmxt_task_disable(NULL); +#endif /* preserve current time */ - delta = xtime.tv_sec - RCNR; - - /* - * Temporary solution. This won't be necessary once - * we move pxa support into the serial driver - * Save the FF UART - */ - SAVE(FFIER); - SAVE(FFLCR); - SAVE(FFMCR); - SAVE(FFSPR); - SAVE(FFISR); - FFLCR |= 0x80; - SAVE(FFDLL); - SAVE(FFDLH); - FFLCR &= 0xef; - - /* save vital registers */ - SAVE(OSCR); - SAVE(OSMR0); - SAVE(OSMR1); - SAVE(OSMR2); - SAVE(OSMR3); - SAVE(OIER); + rtc.tv_sec = RCNR; + rtc.tv_nsec = 0; + save_time_delta(&delta, &rtc); + 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); - CKEN = 0; + 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 /* Clear sleep reset status */ RCSR = RCSR_SMR; - /* set resume return address */ - PSPR = virt_to_phys(pxa_cpu_resume); - /* 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; /* *** go zzz *** */ - pxa_cpu_suspend(); + pxa_cpu_pm_enter(state); + + cpu_init(); /* after sleeping, validate the checksum */ checksum = 0; @@ -139,28 +147,33 @@ static int pxa_pm_enter(u32 state) #ifdef CONFIG_ARCH_LUBBOCK LUB_HEXLED = 0xbadbadc5; #endif - while (1); + while (1) + pxa_cpu_pm_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(GRER0); RESTORE(GRER1); RESTORE(GRER2); - RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); 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_PH; - - RESTORE(OSMR0); - RESTORE(OSMR1); - RESTORE(OSMR2); - RESTORE(OSMR3); - RESTORE(OSCR); - RESTORE(OIER); + PSSR = PSSR_RDH | PSSR_PH; RESTORE(CKEN); @@ -168,24 +181,11 @@ static int pxa_pm_enter(u32 state) ICCR = 1; RESTORE(ICMR); - /* - * Temporary solution. This won't be necessary once - * we move pxa support into the serial driver. - * Restore the FF UART. - */ - RESTORE(FFMCR); - RESTORE(FFSPR); - RESTORE(FFLCR); - FFLCR |= 0x80; - RESTORE(FFDLH); - RESTORE(FFDLL); - RESTORE(FFLCR); - RESTORE(FFISR); - FFFCR = 0x07; - RESTORE(FFIER); + RESTORE(PSTR); /* restore current time */ - xtime.tv_sec = RCNR + delta; + rtc.tv_sec = RCNR; + restore_time_delta(&delta, &rtc); #ifdef DEBUG printk(KERN_DEBUG "*** made it back from resume\n"); @@ -194,6 +194,8 @@ static int pxa_pm_enter(u32 state) return 0; } +EXPORT_SYMBOL_GPL(pxa_pm_enter); + unsigned long sleep_phys_sp(void *sp) { return virt_to_phys(sp); @@ -202,19 +204,25 @@ unsigned long sleep_phys_sp(void *sp) /* * Called after processes are frozen, but before we shut down devices. */ -static int pxa_pm_prepare(u32 state) +int pxa_pm_prepare(suspend_state_t state) { - return 0; + extern int pxa_cpu_pm_prepare(suspend_state_t state); + + return pxa_cpu_pm_prepare(state); } +EXPORT_SYMBOL_GPL(pxa_pm_prepare); + /* * Called after devices are re-setup, but before processes are thawed. */ -static int pxa_pm_finish(u32 state) +int pxa_pm_finish(suspend_state_t state) { return 0; } +EXPORT_SYMBOL_GPL(pxa_pm_finish); + /* * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. */ @@ -231,4 +239,4 @@ static int __init pxa_pm_init(void) return 0; } -late_initcall(pxa_pm_init); +device_initcall(pxa_pm_init);