aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/vfp
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/vfp')
-rw-r--r--arch/arm/vfp/vfp.h2
-rw-r--r--arch/arm/vfp/vfphw.S2
-rw-r--r--arch/arm/vfp/vfpmodule.c56
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)
381extern void vfp_save_state(void *location, u32 fpexc); 381extern 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
173ENDPROC(vfp_support_entry) 173ENDPROC(vfp_support_entry)
174 174
175#ifdef CONFIG_SMP 175#if defined(CONFIG_SMP) || defined(CONFIG_PM)
176ENTRY(vfp_save_state) 176ENTRY(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
328static 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
348static 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
359static struct sysdev_class vfp_pm_sysclass = {
360 .name = "vfp",
361 .suspend = vfp_pm_suspend,
362 .resume = vfp_pm_resume,
363};
364
365static struct sys_device vfp_pm_sysdev = {
366 .cls = &vfp_pm_sysclass,
367};
368
369static void vfp_pm_init(void)
370{
371 sysdev_class_register(&vfp_pm_sysclass);
372 sysdev_register(&vfp_pm_sysdev);
373}
374
375
376#else
377static 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