diff options
Diffstat (limited to 'arch/arm/mach-pxa/pm.c')
-rw-r--r-- | arch/arm/mach-pxa/pm.c | 169 |
1 files changed, 44 insertions, 125 deletions
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 @@ | |||
24 | #include <asm/arch/lubbock.h> | 24 | #include <asm/arch/lubbock.h> |
25 | #include <asm/mach/time.h> | 25 | #include <asm/mach/time.h> |
26 | 26 | ||
27 | 27 | struct pxa_cpu_pm_fns *pxa_cpu_pm_fns; | |
28 | /* | 28 | static unsigned long *sleep_save; |
29 | * Debug macros | ||
30 | */ | ||
31 | #undef DEBUG | ||
32 | |||
33 | #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x | ||
34 | #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] | ||
35 | |||
36 | #define RESTORE_GPLEVEL(n) do { \ | ||
37 | GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \ | ||
38 | GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \ | ||
39 | } while (0) | ||
40 | |||
41 | /* | ||
42 | * List of global PXA peripheral registers to preserve. | ||
43 | * More ones like CP and general purpose register values are preserved | ||
44 | * with the stack pointer in sleep.S. | ||
45 | */ | ||
46 | enum { SLEEP_SAVE_START = 0, | ||
47 | |||
48 | SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, SLEEP_SAVE_GPLR3, | ||
49 | SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, SLEEP_SAVE_GPDR3, | ||
50 | SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, SLEEP_SAVE_GRER3, | ||
51 | SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, SLEEP_SAVE_GFER3, | ||
52 | SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3, | ||
53 | |||
54 | SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U, | ||
55 | SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U, | ||
56 | SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U, | ||
57 | SLEEP_SAVE_GAFR3_L, SLEEP_SAVE_GAFR3_U, | ||
58 | |||
59 | SLEEP_SAVE_PSTR, | ||
60 | |||
61 | SLEEP_SAVE_ICMR, | ||
62 | SLEEP_SAVE_CKEN, | ||
63 | |||
64 | #ifdef CONFIG_PXA27x | ||
65 | SLEEP_SAVE_MDREFR, | ||
66 | SLEEP_SAVE_PWER, SLEEP_SAVE_PCFR, SLEEP_SAVE_PRER, | ||
67 | SLEEP_SAVE_PFER, SLEEP_SAVE_PKWR, | ||
68 | #endif | ||
69 | |||
70 | SLEEP_SAVE_CKSUM, | ||
71 | |||
72 | SLEEP_SAVE_SIZE | ||
73 | }; | ||
74 | |||
75 | 29 | ||
76 | int pxa_pm_enter(suspend_state_t state) | 30 | int pxa_pm_enter(suspend_state_t state) |
77 | { | 31 | { |
78 | unsigned long sleep_save[SLEEP_SAVE_SIZE]; | 32 | unsigned long sleep_save_checksum = 0, checksum = 0; |
79 | unsigned long checksum = 0; | ||
80 | int i; | 33 | int i; |
81 | extern void pxa_cpu_pm_enter(suspend_state_t state); | ||
82 | 34 | ||
83 | #ifdef CONFIG_IWMMXT | 35 | #ifdef CONFIG_IWMMXT |
84 | /* force any iWMMXt context to ram **/ | 36 | /* force any iWMMXt context to ram **/ |
@@ -86,100 +38,35 @@ int pxa_pm_enter(suspend_state_t state) | |||
86 | iwmmxt_task_disable(NULL); | 38 | iwmmxt_task_disable(NULL); |
87 | #endif | 39 | #endif |
88 | 40 | ||
89 | SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2); | 41 | pxa_cpu_pm_fns->save(sleep_save); |
90 | SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2); | ||
91 | SAVE(GRER0); SAVE(GRER1); SAVE(GRER2); | ||
92 | SAVE(GFER0); SAVE(GFER1); SAVE(GFER2); | ||
93 | SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2); | ||
94 | |||
95 | SAVE(GAFR0_L); SAVE(GAFR0_U); | ||
96 | SAVE(GAFR1_L); SAVE(GAFR1_U); | ||
97 | SAVE(GAFR2_L); SAVE(GAFR2_U); | ||
98 | |||
99 | #ifdef CONFIG_PXA27x | ||
100 | SAVE(MDREFR); | ||
101 | SAVE(GPLR3); SAVE(GPDR3); SAVE(GRER3); SAVE(GFER3); SAVE(PGSR3); | ||
102 | SAVE(GAFR3_L); SAVE(GAFR3_U); | ||
103 | SAVE(PWER); SAVE(PCFR); SAVE(PRER); | ||
104 | SAVE(PFER); SAVE(PKWR); | ||
105 | #endif | ||
106 | |||
107 | SAVE(ICMR); | ||
108 | ICMR = 0; | ||
109 | |||
110 | SAVE(CKEN); | ||
111 | SAVE(PSTR); | ||
112 | |||
113 | /* Note: wake up source are set up in each machine specific files */ | ||
114 | |||
115 | /* clear GPIO transition detect bits */ | ||
116 | GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2; | ||
117 | #ifdef CONFIG_PXA27x | ||
118 | GEDR3 = GEDR3; | ||
119 | #endif | ||
120 | 42 | ||
121 | /* Clear sleep reset status */ | 43 | /* Clear sleep reset status */ |
122 | RCSR = RCSR_SMR; | 44 | RCSR = RCSR_SMR; |
123 | 45 | ||
124 | /* before sleeping, calculate and save a checksum */ | 46 | /* before sleeping, calculate and save a checksum */ |
125 | for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++) | 47 | for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++) |
126 | checksum += sleep_save[i]; | 48 | sleep_save_checksum += sleep_save[i]; |
127 | sleep_save[SLEEP_SAVE_CKSUM] = checksum; | ||
128 | 49 | ||
129 | /* *** go zzz *** */ | 50 | /* *** go zzz *** */ |
130 | pxa_cpu_pm_enter(state); | 51 | pxa_cpu_pm_fns->enter(state); |
131 | |||
132 | cpu_init(); | 52 | cpu_init(); |
133 | 53 | ||
134 | /* after sleeping, validate the checksum */ | 54 | /* after sleeping, validate the checksum */ |
135 | checksum = 0; | 55 | for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++) |
136 | for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++) | ||
137 | checksum += sleep_save[i]; | 56 | checksum += sleep_save[i]; |
138 | 57 | ||
139 | /* if invalid, display message and wait for a hardware reset */ | 58 | /* if invalid, display message and wait for a hardware reset */ |
140 | if (checksum != sleep_save[SLEEP_SAVE_CKSUM]) { | 59 | if (checksum != sleep_save_checksum) { |
141 | #ifdef CONFIG_ARCH_LUBBOCK | 60 | #ifdef CONFIG_ARCH_LUBBOCK |
142 | LUB_HEXLED = 0xbadbadc5; | 61 | LUB_HEXLED = 0xbadbadc5; |
143 | #endif | 62 | #endif |
144 | while (1) | 63 | while (1) |
145 | pxa_cpu_pm_enter(state); | 64 | pxa_cpu_pm_fns->enter(state); |
146 | } | 65 | } |
147 | 66 | ||
148 | /* ensure not to come back here if it wasn't intended */ | 67 | pxa_cpu_pm_fns->restore(sleep_save); |
149 | PSPR = 0; | ||
150 | |||
151 | /* restore registers */ | ||
152 | RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2); | ||
153 | RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2); | ||
154 | RESTORE(GAFR0_L); RESTORE(GAFR0_U); | ||
155 | RESTORE(GAFR1_L); RESTORE(GAFR1_U); | ||
156 | RESTORE(GAFR2_L); RESTORE(GAFR2_U); | ||
157 | RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2); | ||
158 | RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); | ||
159 | RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2); | ||
160 | |||
161 | #ifdef CONFIG_PXA27x | ||
162 | RESTORE(MDREFR); | ||
163 | RESTORE_GPLEVEL(3); RESTORE(GPDR3); | ||
164 | RESTORE(GAFR3_L); RESTORE(GAFR3_U); | ||
165 | RESTORE(GRER3); RESTORE(GFER3); RESTORE(PGSR3); | ||
166 | RESTORE(PWER); RESTORE(PCFR); RESTORE(PRER); | ||
167 | RESTORE(PFER); RESTORE(PKWR); | ||
168 | #endif | ||
169 | |||
170 | PSSR = PSSR_RDH | PSSR_PH; | ||
171 | |||
172 | RESTORE(CKEN); | ||
173 | |||
174 | ICLR = 0; | ||
175 | ICCR = 1; | ||
176 | RESTORE(ICMR); | ||
177 | 68 | ||
178 | RESTORE(PSTR); | 69 | pr_debug("*** made it back from resume\n"); |
179 | |||
180 | #ifdef DEBUG | ||
181 | printk(KERN_DEBUG "*** made it back from resume\n"); | ||
182 | #endif | ||
183 | 70 | ||
184 | return 0; | 71 | return 0; |
185 | } | 72 | } |
@@ -190,3 +77,35 @@ unsigned long sleep_phys_sp(void *sp) | |||
190 | { | 77 | { |
191 | return virt_to_phys(sp); | 78 | return virt_to_phys(sp); |
192 | } | 79 | } |
80 | |||
81 | static int pxa_pm_valid(suspend_state_t state) | ||
82 | { | ||
83 | if (pxa_cpu_pm_fns) | ||
84 | return pxa_cpu_pm_fns->valid(state); | ||
85 | |||
86 | return -EINVAL; | ||
87 | } | ||
88 | |||
89 | static struct pm_ops pxa_pm_ops = { | ||
90 | .valid = pxa_pm_valid, | ||
91 | .enter = pxa_pm_enter, | ||
92 | }; | ||
93 | |||
94 | static int __init pxa_pm_init(void) | ||
95 | { | ||
96 | if (!pxa_cpu_pm_fns) { | ||
97 | printk(KERN_ERR "no valid pxa_cpu_pm_fns defined\n"); | ||
98 | return -EINVAL; | ||
99 | } | ||
100 | |||
101 | sleep_save = kmalloc(pxa_cpu_pm_fns->save_size, GFP_KERNEL); | ||
102 | if (!sleep_save) { | ||
103 | printk(KERN_ERR "failed to alloc memory for pm save\n"); | ||
104 | return -ENOMEM; | ||
105 | } | ||
106 | |||
107 | pm_set_ops(&pxa_pm_ops); | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | device_initcall(pxa_pm_init); | ||