aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVille Syrjala <syrjala@sci.fi>2009-06-30 14:41:40 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-30 21:56:01 -0400
commiteafad22a05fdaca60f06433ffe8810aaa920d539 (patch)
treedf799e81ce5b2e9d63dbece7d9c2f4beff83e618
parent50efacf6711e6c75595afd9b92aa15c1e4f7c79d (diff)
atyfb: fix HP OmniBook 500 reboot hang
Apparently HP OmniBook 500's BIOS doesn't like the way atyfb reprograms the hardware. The BIOS will simply hang after a reboot. Fix the problem by restoring the hardware to it's original state on reboot. Signed-off-by: Ville Syrjala <syrjala@sci.fi> Cc: Mikulas Patocka <mpatocka@redhat.com> Cc: Krzysztof Helt <krzysztof.h1@poczta.fm> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/video/aty/atyfb.h2
-rw-r--r--drivers/video/aty/atyfb_base.c89
2 files changed, 82 insertions, 9 deletions
diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h
index 7691e73823d3..0369653b5d88 100644
--- a/drivers/video/aty/atyfb.h
+++ b/drivers/video/aty/atyfb.h
@@ -187,6 +187,8 @@ struct atyfb_par {
187 int mtrr_reg; 187 int mtrr_reg;
188#endif 188#endif
189 u32 mem_cntl; 189 u32 mem_cntl;
190 struct crtc saved_crtc;
191 union aty_pll saved_pll;
190}; 192};
191 193
192 /* 194 /*
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 1207c208a30b..06782906daf5 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -66,6 +66,8 @@
66#include <linux/spinlock.h> 66#include <linux/spinlock.h>
67#include <linux/wait.h> 67#include <linux/wait.h>
68#include <linux/backlight.h> 68#include <linux/backlight.h>
69#include <linux/reboot.h>
70#include <linux/dmi.h>
69 71
70#include <asm/io.h> 72#include <asm/io.h>
71#include <linux/uaccess.h> 73#include <linux/uaccess.h>
@@ -249,8 +251,6 @@ static int aty_init(struct fb_info *info);
249static int store_video_par(char *videopar, unsigned char m64_num); 251static int store_video_par(char *videopar, unsigned char m64_num);
250#endif 252#endif
251 253
252static struct crtc saved_crtc;
253static union aty_pll saved_pll;
254static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc); 254static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc);
255 255
256static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc); 256static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc);
@@ -261,6 +261,8 @@ static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info);
261static int read_aty_sense(const struct atyfb_par *par); 261static int read_aty_sense(const struct atyfb_par *par);
262#endif 262#endif
263 263
264static DEFINE_MUTEX(reboot_lock);
265static struct fb_info *reboot_info;
264 266
265 /* 267 /*
266 * Interface used by the world 268 * Interface used by the world
@@ -2390,9 +2392,9 @@ static int __devinit aty_init(struct fb_info *info)
2390#endif /* CONFIG_FB_ATY_CT */ 2392#endif /* CONFIG_FB_ATY_CT */
2391 2393
2392 /* save previous video mode */ 2394 /* save previous video mode */
2393 aty_get_crtc(par, &saved_crtc); 2395 aty_get_crtc(par, &par->saved_crtc);
2394 if(par->pll_ops->get_pll) 2396 if(par->pll_ops->get_pll)
2395 par->pll_ops->get_pll(info, &saved_pll); 2397 par->pll_ops->get_pll(info, &par->saved_pll);
2396 2398
2397 par->mem_cntl = aty_ld_le32(MEM_CNTL, par); 2399 par->mem_cntl = aty_ld_le32(MEM_CNTL, par);
2398 gtb_memsize = M64_HAS(GTB_DSP); 2400 gtb_memsize = M64_HAS(GTB_DSP);
@@ -2667,8 +2669,8 @@ static int __devinit aty_init(struct fb_info *info)
2667 2669
2668aty_init_exit: 2670aty_init_exit:
2669 /* restore video mode */ 2671 /* restore video mode */
2670 aty_set_crtc(par, &saved_crtc); 2672 aty_set_crtc(par, &par->saved_crtc);
2671 par->pll_ops->set_pll(info, &saved_pll); 2673 par->pll_ops->set_pll(info, &par->saved_pll);
2672 2674
2673#ifdef CONFIG_MTRR 2675#ifdef CONFIG_MTRR
2674 if (par->mtrr_reg >= 0) { 2676 if (par->mtrr_reg >= 0) {
@@ -3502,6 +3504,11 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi
3502 par->mmap_map[1].prot_flag = _PAGE_E; 3504 par->mmap_map[1].prot_flag = _PAGE_E;
3503#endif /* __sparc__ */ 3505#endif /* __sparc__ */
3504 3506
3507 mutex_lock(&reboot_lock);
3508 if (!reboot_info)
3509 reboot_info = info;
3510 mutex_unlock(&reboot_lock);
3511
3505 return 0; 3512 return 0;
3506 3513
3507err_release_io: 3514err_release_io:
@@ -3614,8 +3621,8 @@ static void __devexit atyfb_remove(struct fb_info *info)
3614 struct atyfb_par *par = (struct atyfb_par *) info->par; 3621 struct atyfb_par *par = (struct atyfb_par *) info->par;
3615 3622
3616 /* restore video mode */ 3623 /* restore video mode */
3617 aty_set_crtc(par, &saved_crtc); 3624 aty_set_crtc(par, &par->saved_crtc);
3618 par->pll_ops->set_pll(info, &saved_pll); 3625 par->pll_ops->set_pll(info, &par->saved_pll);
3619 3626
3620 unregister_framebuffer(info); 3627 unregister_framebuffer(info);
3621 3628
@@ -3661,6 +3668,11 @@ static void __devexit atyfb_pci_remove(struct pci_dev *pdev)
3661{ 3668{
3662 struct fb_info *info = pci_get_drvdata(pdev); 3669 struct fb_info *info = pci_get_drvdata(pdev);
3663 3670
3671 mutex_lock(&reboot_lock);
3672 if (reboot_info == info)
3673 reboot_info = NULL;
3674 mutex_unlock(&reboot_lock);
3675
3664 atyfb_remove(info); 3676 atyfb_remove(info);
3665} 3677}
3666 3678
@@ -3808,6 +3820,56 @@ static int __init atyfb_setup(char *options)
3808} 3820}
3809#endif /* MODULE */ 3821#endif /* MODULE */
3810 3822
3823static int atyfb_reboot_notify(struct notifier_block *nb,
3824 unsigned long code, void *unused)
3825{
3826 struct atyfb_par *par;
3827
3828 if (code != SYS_RESTART)
3829 return NOTIFY_DONE;
3830
3831 mutex_lock(&reboot_lock);
3832
3833 if (!reboot_info)
3834 goto out;
3835
3836 if (!lock_fb_info(reboot_info))
3837 goto out;
3838
3839 par = reboot_info->par;
3840
3841 /*
3842 * HP OmniBook 500's BIOS doesn't like the state of the
3843 * hardware after atyfb has been used. Restore the hardware
3844 * to the original state to allow successful reboots.
3845 */
3846 aty_set_crtc(par, &par->saved_crtc);
3847 par->pll_ops->set_pll(reboot_info, &par->saved_pll);
3848
3849 unlock_fb_info(reboot_info);
3850 out:
3851 mutex_unlock(&reboot_lock);
3852
3853 return NOTIFY_DONE;
3854}
3855
3856static struct notifier_block atyfb_reboot_notifier = {
3857 .notifier_call = atyfb_reboot_notify,
3858};
3859
3860static const struct dmi_system_id atyfb_reboot_ids[] = {
3861 {
3862 .ident = "HP OmniBook 500",
3863 .matches = {
3864 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
3865 DMI_MATCH(DMI_PRODUCT_NAME, "HP OmniBook PC"),
3866 DMI_MATCH(DMI_PRODUCT_VERSION, "HP OmniBook 500 FA"),
3867 },
3868 },
3869
3870 { }
3871};
3872
3811static int __init atyfb_init(void) 3873static int __init atyfb_init(void)
3812{ 3874{
3813 int err1 = 1, err2 = 1; 3875 int err1 = 1, err2 = 1;
@@ -3826,11 +3888,20 @@ static int __init atyfb_init(void)
3826 err2 = atyfb_atari_probe(); 3888 err2 = atyfb_atari_probe();
3827#endif 3889#endif
3828 3890
3829 return (err1 && err2) ? -ENODEV : 0; 3891 if (err1 && err2)
3892 return -ENODEV;
3893
3894 if (dmi_check_system(atyfb_reboot_ids))
3895 register_reboot_notifier(&atyfb_reboot_notifier);
3896
3897 return 0;
3830} 3898}
3831 3899
3832static void __exit atyfb_exit(void) 3900static void __exit atyfb_exit(void)
3833{ 3901{
3902 if (dmi_check_system(atyfb_reboot_ids))
3903 unregister_reboot_notifier(&atyfb_reboot_notifier);
3904
3834#ifdef CONFIG_PCI 3905#ifdef CONFIG_PCI
3835 pci_unregister_driver(&atyfb_driver); 3906 pci_unregister_driver(&atyfb_driver);
3836#endif 3907#endif