aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/vfp/vfpmodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/vfp/vfpmodule.c')
-rw-r--r--arch/arm/vfp/vfpmodule.c65
1 files changed, 65 insertions, 0 deletions
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index c0d2c9bb952b..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,12 +420,22 @@ 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
371 * in place; report VFP support to userspace. 427 * in place; report VFP support to userspace.
372 */ 428 */
373 elf_hwcap |= HWCAP_VFP; 429 elf_hwcap |= HWCAP_VFP;
430#ifdef CONFIG_NEON
431 /*
432 * Check for the presence of the Advanced SIMD
433 * load/store instructions, integer and single
434 * precision floating point operations.
435 */
436 if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100)
437 elf_hwcap |= HWCAP_NEON;
438#endif
374 } 439 }
375 return 0; 440 return 0;
376} 441}