diff options
Diffstat (limited to 'arch/arm/vfp')
-rw-r--r-- | arch/arm/vfp/vfp.h | 2 | ||||
-rw-r--r-- | arch/arm/vfp/vfphw.S | 2 | ||||
-rw-r--r-- | arch/arm/vfp/vfpmodule.c | 56 |
3 files changed, 58 insertions, 2 deletions
diff --git a/arch/arm/vfp/vfp.h b/arch/arm/vfp/vfp.h index c85860bad585..8de86e4feada 100644 --- a/arch/arm/vfp/vfp.h +++ b/arch/arm/vfp/vfp.h | |||
@@ -377,6 +377,6 @@ struct op { | |||
377 | u32 flags; | 377 | u32 flags; |
378 | }; | 378 | }; |
379 | 379 | ||
380 | #ifdef CONFIG_SMP | 380 | #if defined(CONFIG_SMP) || defined(CONFIG_PM) |
381 | extern void vfp_save_state(void *location, u32 fpexc); | 381 | extern void vfp_save_state(void *location, u32 fpexc); |
382 | #endif | 382 | #endif |
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S index 3c73aafe3e01..c92a08bd6a86 100644 --- a/arch/arm/vfp/vfphw.S +++ b/arch/arm/vfp/vfphw.S | |||
@@ -172,7 +172,7 @@ process_exception: | |||
172 | @ retry the faulted instruction | 172 | @ retry the faulted instruction |
173 | ENDPROC(vfp_support_entry) | 173 | ENDPROC(vfp_support_entry) |
174 | 174 | ||
175 | #ifdef CONFIG_SMP | 175 | #if defined(CONFIG_SMP) || defined(CONFIG_PM) |
176 | ENTRY(vfp_save_state) | 176 | ENTRY(vfp_save_state) |
177 | @ Save the current VFP state | 177 | @ Save the current VFP state |
178 | @ r0 - save location | 178 | @ r0 - save location |
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 67ca340a7c85..9f476a1be2ca 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c | |||
@@ -322,6 +322,61 @@ static void vfp_enable(void *unused) | |||
322 | set_copro_access(access | CPACC_FULL(10) | CPACC_FULL(11)); | 322 | set_copro_access(access | CPACC_FULL(10) | CPACC_FULL(11)); |
323 | } | 323 | } |
324 | 324 | ||
325 | #ifdef CONFIG_PM | ||
326 | #include <linux/sysdev.h> | ||
327 | |||
328 | static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state) | ||
329 | { | ||
330 | struct thread_info *ti = current_thread_info(); | ||
331 | u32 fpexc = fmrx(FPEXC); | ||
332 | |||
333 | /* if vfp is on, then save state for resumption */ | ||
334 | if (fpexc & FPEXC_EN) { | ||
335 | printk(KERN_DEBUG "%s: saving vfp state\n", __func__); | ||
336 | vfp_save_state(&ti->vfpstate, fpexc); | ||
337 | |||
338 | /* disable, just in case */ | ||
339 | fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); | ||
340 | } | ||
341 | |||
342 | /* clear any information we had about last context state */ | ||
343 | memset(last_VFP_context, 0, sizeof(last_VFP_context)); | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static int vfp_pm_resume(struct sys_device *dev) | ||
349 | { | ||
350 | /* ensure we have access to the vfp */ | ||
351 | vfp_enable(NULL); | ||
352 | |||
353 | /* and disable it to ensure the next usage restores the state */ | ||
354 | fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static struct sysdev_class vfp_pm_sysclass = { | ||
360 | .name = "vfp", | ||
361 | .suspend = vfp_pm_suspend, | ||
362 | .resume = vfp_pm_resume, | ||
363 | }; | ||
364 | |||
365 | static struct sys_device vfp_pm_sysdev = { | ||
366 | .cls = &vfp_pm_sysclass, | ||
367 | }; | ||
368 | |||
369 | static void vfp_pm_init(void) | ||
370 | { | ||
371 | sysdev_class_register(&vfp_pm_sysclass); | ||
372 | sysdev_register(&vfp_pm_sysdev); | ||
373 | } | ||
374 | |||
375 | |||
376 | #else | ||
377 | static inline void vfp_pm_init(void) { } | ||
378 | #endif /* CONFIG_PM */ | ||
379 | |||
325 | #include <linux/smp.h> | 380 | #include <linux/smp.h> |
326 | 381 | ||
327 | /* | 382 | /* |
@@ -365,6 +420,7 @@ static int __init vfp_init(void) | |||
365 | vfp_vector = vfp_support_entry; | 420 | vfp_vector = vfp_support_entry; |
366 | 421 | ||
367 | thread_register_notifier(&vfp_notifier_block); | 422 | thread_register_notifier(&vfp_notifier_block); |
423 | vfp_pm_init(); | ||
368 | 424 | ||
369 | /* | 425 | /* |
370 | * We detected VFP, and the support code is | 426 | * We detected VFP, and the support code is |