aboutsummaryrefslogtreecommitdiffstats
path: root/recipes/linux/linux-omap-pm-2.6.29/vfp/01-vfp-pm.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes/linux/linux-omap-pm-2.6.29/vfp/01-vfp-pm.patch')
-rw-r--r--recipes/linux/linux-omap-pm-2.6.29/vfp/01-vfp-pm.patch128
1 files changed, 128 insertions, 0 deletions
diff --git a/recipes/linux/linux-omap-pm-2.6.29/vfp/01-vfp-pm.patch b/recipes/linux/linux-omap-pm-2.6.29/vfp/01-vfp-pm.patch
new file mode 100644
index 0000000000..70d4d1efc5
--- /dev/null
+++ b/recipes/linux/linux-omap-pm-2.6.29/vfp/01-vfp-pm.patch
@@ -0,0 +1,128 @@
+From: Ben Dooks <ben-linux@fluff.org>
+Date: Thu, 18 Dec 2008 10:26:54 +0000 (+0100)
+Subject: 5349/1: VFP: Add PM code to save and restore current VFP state
+X-Git-Url: http://siarhei.siamashka.name/gitweb/?p=linux-omap-2.6.git;a=commitdiff_plain;h=d504d72ad38e54b5feda67e956834348d6a500e1
+
+5349/1: VFP: Add PM code to save and restore current VFP state
+
+[ARM] 5349/1: VFP: Add PM code to save and restore current VFP state
+
+When CONFIG_PM is selected, the VFP code does not have any handler
+installed to deal with either saving the VFP state of the current
+task, nor does it do anything to try and restore the VFP after a
+resume.
+
+On resume, the VFP will have been reset and the co-processor access
+control registers are in an indeterminate state (very probably the
+CP10 and CP11 the VFP uses will have been disabled by the ARM core
+reset). When this happens, resume will break as soon as it tries to
+unfreeze the tasks and restart scheduling.
+
+Add a sys device to allow us to hook the suspend call to save the
+current thread state if the thread is using VFP and a resume hook
+which restores the CP10/CP11 access and ensures the VFP is disabled
+so that the lazy swapping will take place on next access.
+
+Signed-off-by: Ben Dooks <ben-linux@fluff.org>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+
+diff --git a/arch/arm/vfp/vfp.h b/arch/arm/vfp/vfp.h
+index c85860b..8de86e4 100644
+--- a/arch/arm/vfp/vfp.h
++++ b/arch/arm/vfp/vfp.h
+@@ -377,6 +377,6 @@ struct op {
+ u32 flags;
+ };
+
+-#ifdef CONFIG_SMP
++#if defined(CONFIG_SMP) || defined(CONFIG_PM)
+ extern void vfp_save_state(void *location, u32 fpexc);
+ #endif
+diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
+index a62dcf7..b21f43f 100644
+--- a/arch/arm/vfp/vfphw.S
++++ b/arch/arm/vfp/vfphw.S
+@@ -166,7 +166,7 @@ process_exception:
+ @ retry the faulted instruction
+ ENDPROC(vfp_support_entry)
+
+-#ifdef CONFIG_SMP
++#if defined(CONFIG_SMP) || defined(CONFIG_PM)
+ ENTRY(vfp_save_state)
+ @ Save the current VFP state
+ @ r0 - save location
+diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
+index 67ca340..9f476a1 100644
+--- a/arch/arm/vfp/vfpmodule.c
++++ b/arch/arm/vfp/vfpmodule.c
+@@ -322,6 +322,61 @@ static void vfp_enable(void *unused)
+ set_copro_access(access | CPACC_FULL(10) | CPACC_FULL(11));
+ }
+
++#ifdef CONFIG_PM
++#include <linux/sysdev.h>
++
++static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state)
++{
++ struct thread_info *ti = current_thread_info();
++ u32 fpexc = fmrx(FPEXC);
++
++ /* if vfp is on, then save state for resumption */
++ if (fpexc & FPEXC_EN) {
++ printk(KERN_DEBUG "%s: saving vfp state\n", __func__);
++ vfp_save_state(&ti->vfpstate, fpexc);
++
++ /* disable, just in case */
++ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
++ }
++
++ /* clear any information we had about last context state */
++ memset(last_VFP_context, 0, sizeof(last_VFP_context));
++
++ return 0;
++}
++
++static int vfp_pm_resume(struct sys_device *dev)
++{
++ /* ensure we have access to the vfp */
++ vfp_enable(NULL);
++
++ /* and disable it to ensure the next usage restores the state */
++ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
++
++ return 0;
++}
++
++static struct sysdev_class vfp_pm_sysclass = {
++ .name = "vfp",
++ .suspend = vfp_pm_suspend,
++ .resume = vfp_pm_resume,
++};
++
++static struct sys_device vfp_pm_sysdev = {
++ .cls = &vfp_pm_sysclass,
++};
++
++static void vfp_pm_init(void)
++{
++ sysdev_class_register(&vfp_pm_sysclass);
++ sysdev_register(&vfp_pm_sysdev);
++}
++
++
++#else
++static inline void vfp_pm_init(void) { }
++#endif /* CONFIG_PM */
++
+ #include <linux/smp.h>
+
+ /*
+@@ -365,6 +420,7 @@ static int __init vfp_init(void)
+ vfp_vector = vfp_support_entry;
+
+ thread_register_notifier(&vfp_notifier_block);
++ vfp_pm_init();
+
+ /*
+ * We detected VFP, and the support code is