atyfb: fix HP OmniBook 500 reboot hang
[safe/jmp/linux-2.6] / drivers / video / aty / atyfb_base.c
index 0c7bf75..0678290 100644 (file)
@@ -26,7 +26,7 @@
  *                        Anthony Tong <atong@uiuc.edu>
  *
  *  Generic LCD support written by Daniel Mantione, ported from 2.4.20 by Alex Kern
- *  Many Thanks to Ville Syrjälä for patches and fixing nasting 16 bit color bug.
+ *  Many Thanks to Ville Syrjälä for patches and fixing nasting 16 bit color bug.
  *
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License. See the file COPYING in the main directory of this archive for
 #include <linux/spinlock.h>
 #include <linux/wait.h>
 #include <linux/backlight.h>
+#include <linux/reboot.h>
+#include <linux/dmi.h>
 
 #include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #include <video/mach64.h>
 #include "atyfb.h"
 #if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || \
 defined (CONFIG_FB_ATY_GENERIC_LCD) || defined(CONFIG_FB_ATY_BACKLIGHT)
 static const u32 lt_lcd_regs[] = {
-       CONFIG_PANEL_LG,
+       CNFG_PANEL_LG,
        LCD_GEN_CNTL_LG,
        DSTN_CONTROL_LG,
        HFB_PITCH_ADDR_LG,
@@ -244,13 +246,11 @@ static int atyfb_sync(struct fb_info *info);
      */
 
 static int aty_init(struct fb_info *info);
-static void aty_resume_chip(struct fb_info *info);
+
 #ifdef CONFIG_ATARI
 static int store_video_par(char *videopar, unsigned char m64_num);
 #endif
 
-static struct crtc saved_crtc;
-static union aty_pll saved_pll;
 static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc);
 
 static 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);
 static int read_aty_sense(const struct atyfb_par *par);
 #endif
 
+static DEFINE_MUTEX(reboot_lock);
+static struct fb_info *reboot_info;
 
     /*
      *  Interface used by the world
@@ -424,7 +426,6 @@ static struct {
 #endif /* CONFIG_FB_ATY_CT */
 };
 
-/* can not fail */
 static int __devinit correct_chipset(struct atyfb_par *par)
 {
        u8 rev;
@@ -437,6 +438,9 @@ static int __devinit correct_chipset(struct atyfb_par *par)
                if (par->pci_id == aty_chips[i].pci_id)
                        break;
 
+       if (i < 0)
+               return -ENODEV;
+
        name = aty_chips[i].name;
        par->pll_limits.pll_max = aty_chips[i].pll;
        par->pll_limits.mclk = aty_chips[i].mclk;
@@ -444,7 +448,7 @@ static int __devinit correct_chipset(struct atyfb_par *par)
        par->pll_limits.ecp_max = aty_chips[i].ecp_max;
        par->features = aty_chips[i].features;
 
-       chip_id = aty_ld_le32(CONFIG_CHIP_ID, par);
+       chip_id = aty_ld_le32(CNFG_CHIP_ID, par);
        type = chip_id & CFG_CHIP_TYPE;
        rev = (chip_id & CFG_CHIP_REV) >> 24;
 
@@ -541,8 +545,6 @@ static char ram_off[] __devinitdata = "OFF";
 #endif /* CONFIG_FB_ATY_CT */
 
 
-static u32 pseudo_palette[16];
-
 #ifdef CONFIG_FB_ATY_GX
 static char *aty_gx_ram[8] __devinitdata = {
        ram_dram, ram_vram, ram_vram, ram_dram,
@@ -629,7 +631,7 @@ static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc)
                    crtc->lcd_index = aty_ld_le32(LCD_INDEX, par);
                    aty_st_le32(LCD_INDEX, crtc->lcd_index, par);
                }
-               crtc->lcd_config_panel = aty_ld_lcd(CONFIG_PANEL, par);
+               crtc->lcd_config_panel = aty_ld_lcd(CNFG_PANEL, par);
                crtc->lcd_gen_cntl = aty_ld_lcd(LCD_GEN_CNTL, par);
 
 
@@ -676,7 +678,7 @@ static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc)
                aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl & ~(CRTC_EXT_DISP_EN | CRTC_EN), par);
 
                /* update non-shadow registers first */
-               aty_st_lcd(CONFIG_PANEL, crtc->lcd_config_panel, par);
+               aty_st_lcd(CNFG_PANEL, crtc->lcd_config_panel, par);
                aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl &
                        ~(CRTC_RW_SELECT | SHADOW_EN | SHADOW_RW_EN), par);
 
@@ -858,7 +860,7 @@ static int aty_var_to_crtc(const struct fb_info *info,
                if (!M64_HAS(MOBIL_BUS))
                        crtc->lcd_index |= CRTC2_DISPLAY_DIS;
 
-               crtc->lcd_config_panel = aty_ld_lcd(CONFIG_PANEL, par) | 0x4000;
+               crtc->lcd_config_panel = aty_ld_lcd(CNFG_PANEL, par) | 0x4000;
                crtc->lcd_gen_cntl = aty_ld_lcd(LCD_GEN_CNTL, par) & ~CRTC_RW_SELECT;
 
                crtc->lcd_gen_cntl &=
@@ -1915,61 +1917,6 @@ static int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
                par->mmaped = 1;
        return 0;
 }
-
-static struct {
-       u32 yoffset;
-       u8 r[2][256];
-       u8 g[2][256];
-       u8 b[2][256];
-} atyfb_save;
-
-static void atyfb_save_palette(struct atyfb_par *par, int enter)
-{
-       int i, tmp;
-
-       for (i = 0; i < 256; i++) {
-               tmp = aty_ld_8(DAC_CNTL, par) & 0xfc;
-               if (M64_HAS(EXTRA_BRIGHT))
-                       tmp |= 0x2;
-               aty_st_8(DAC_CNTL, tmp, par);
-               aty_st_8(DAC_MASK, 0xff, par);
-
-               aty_st_8(DAC_R_INDEX, i, par);
-               atyfb_save.r[enter][i] = aty_ld_8(DAC_DATA, par);
-               atyfb_save.g[enter][i] = aty_ld_8(DAC_DATA, par);
-               atyfb_save.b[enter][i] = aty_ld_8(DAC_DATA, par);
-               aty_st_8(DAC_W_INDEX, i, par);
-               aty_st_8(DAC_DATA, atyfb_save.r[1 - enter][i], par);
-               aty_st_8(DAC_DATA, atyfb_save.g[1 - enter][i], par);
-               aty_st_8(DAC_DATA, atyfb_save.b[1 - enter][i], par);
-       }
-}
-
-static void atyfb_palette(int enter)
-{
-       struct atyfb_par *par;
-       struct fb_info *info;
-       int i;
-
-       for (i = 0; i < FB_MAX; i++) {
-               info = registered_fb[i];
-               if (info && info->fbops == &atyfb_ops) {
-                       par = (struct atyfb_par *) info->par;
-                       
-                       atyfb_save_palette(par, enter);
-                       if (enter) {
-                               atyfb_save.yoffset = info->var.yoffset;
-                               info->var.yoffset = 0;
-                               set_off_pitch(par, info);
-                       } else {
-                               info->var.yoffset = atyfb_save.yoffset;
-                               set_off_pitch(par, info);
-                       }
-                       aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);
-                       break;
-               }
-       }
-}
 #endif /* __sparc__ */
 
 
@@ -2033,7 +1980,7 @@ static int aty_power_mgmt(int sleep, struct atyfb_par *par)
 
        return timeout ? 0 : -EIO;
 }
-#endif
+#endif /* CONFIG_PPC_PMAC */
 
 static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
@@ -2057,9 +2004,15 @@ static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        par->asleep = 1;
        par->lock_blank = 1;
 
+       /* Because we may change PCI D state ourselves, we need to
+        * first save the config space content so the core can
+        * restore it properly on resume.
+        */
+       pci_save_state(pdev);
+
 #ifdef CONFIG_PPC_PMAC
        /* Set chip to "suspend" mode */
-       if (aty_power_mgmt(1, par)) {
+       if (machine_is(powermac) && aty_power_mgmt(1, par)) {
                par->asleep = 0;
                par->lock_blank = 0;
                atyfb_blank(FB_BLANK_UNBLANK, info);
@@ -2078,6 +2031,20 @@ static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        return 0;
 }
 
+static void aty_resume_chip(struct fb_info *info)
+{
+       struct atyfb_par *par = info->par;
+
+       aty_st_le32(MEM_CNTL, par->mem_cntl, par);
+
+       if (par->pll_ops->resume_pll)
+               par->pll_ops->resume_pll(info, &par->pll);
+
+       if (par->aux_start)
+               aty_st_le32(BUS_CNTL,
+                       aty_ld_le32(BUS_CNTL, par) | BUS_APER_REG_DIS, par);
+}
+
 static int atyfb_pci_resume(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
@@ -2088,11 +2055,15 @@ static int atyfb_pci_resume(struct pci_dev *pdev)
 
        acquire_console_sem();
 
+       /* PCI state will have been restored by the core, so
+        * we should be in D0 now with our config space fully
+        * restored
+        */
+
 #ifdef CONFIG_PPC_PMAC
-       if (pdev->dev.power.power_state.event == 2)
+       if (machine_is(powermac) &&
+           pdev->dev.power.power_state.event == PM_EVENT_SUSPEND)
                aty_power_mgmt(0, par);
-#else
-       pci_set_power_state(pdev, PCI_D0);
 #endif
 
        aty_resume_chip(info);
@@ -2141,7 +2112,7 @@ static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
 
 static int aty_bl_update_status(struct backlight_device *bd)
 {
-       struct atyfb_par *par = class_get_devdata(&bd->class_dev);
+       struct atyfb_par *par = bl_get_data(bd);
        unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
        int level;
 
@@ -2286,6 +2257,7 @@ static int __devinit aty_init(struct fb_info *info)
        const char *ramname = NULL, *xtal;
        int gtb_memsize, has_var = 0;
        struct fb_var_screeninfo var;
+       int ret;
 
        init_waitqueue_head(&par->vblank.wait);
        spin_lock_init(&par->int_lock);
@@ -2294,7 +2266,7 @@ static int __devinit aty_init(struct fb_info *info)
        if (!M64_HAS(INTEGRATED)) {
                u32 stat0;
                u8 dac_type, dac_subtype, clk_type;
-               stat0 = aty_ld_le32(CONFIG_STAT0, par);
+               stat0 = aty_ld_le32(CNFG_STAT0, par);
                par->bus_type = (stat0 >> 0) & 0x07;
                par->ram_type = (stat0 >> 3) & 0x07;
                ramname = aty_gx_ram[par->ram_type];
@@ -2364,7 +2336,7 @@ static int __devinit aty_init(struct fb_info *info)
                par->dac_ops = &aty_dac_ct;
                par->pll_ops = &aty_pll_ct;
                par->bus_type = PCI;
-               par->ram_type = (aty_ld_le32(CONFIG_STAT0, par) & 0x07);
+               par->ram_type = (aty_ld_le32(CNFG_STAT0, par) & 0x07);
                ramname = aty_ct_ram[par->ram_type];
                /* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */
                if (par->pll_limits.mclk == 67 && par->ram_type < SDRAM)
@@ -2420,9 +2392,9 @@ static int __devinit aty_init(struct fb_info *info)
 #endif /* CONFIG_FB_ATY_CT */
 
        /* save previous video mode */
-       aty_get_crtc(par, &saved_crtc);
+       aty_get_crtc(par, &par->saved_crtc);
        if(par->pll_ops->get_pll)
-               par->pll_ops->get_pll(info, &saved_pll);
+               par->pll_ops->get_pll(info, &par->saved_pll);
 
        par->mem_cntl = aty_ld_le32(MEM_CNTL, par);
        gtb_memsize = M64_HAS(GTB_DSP);
@@ -2473,7 +2445,7 @@ static int __devinit aty_init(struct fb_info *info)
                }
 
        if (M64_HAS(MAGIC_VRAM_SIZE)) {
-               if (aty_ld_le32(CONFIG_STAT1, par) & 0x40000000)
+               if (aty_ld_le32(CNFG_STAT1, par) & 0x40000000)
                        info->fix.smem_len += 0x400000;
        }
 
@@ -2577,7 +2549,7 @@ static int __devinit aty_init(struct fb_info *info)
 #endif
 
        info->fbops = &atyfb_ops;
-       info->pseudo_palette = pseudo_palette;
+       info->pseudo_palette = par->pseudo_palette;
        info->flags = FBINFO_DEFAULT           |
                      FBINFO_HWACCEL_IMAGEBLIT |
                      FBINFO_HWACCEL_FILLRECT  |
@@ -2667,25 +2639,27 @@ static int __devinit aty_init(struct fb_info *info)
                        var.yres_virtual = var.yres;
        }
 
-       if (atyfb_check_var(&var, info)) {
+       ret = atyfb_check_var(&var, info);
+       if (ret) {
                PRINTKE("can't set default video mode\n");
                goto aty_init_exit;
        }
 
-#ifdef __sparc__
-       atyfb_save_palette(par, 0);
-#endif
-
 #ifdef CONFIG_FB_ATY_CT
        if (!noaccel && M64_HAS(INTEGRATED))
                aty_init_cursor(info);
 #endif /* CONFIG_FB_ATY_CT */
        info->var = var;
 
-       fb_alloc_cmap(&info->cmap, 256, 0);
+       ret = fb_alloc_cmap(&info->cmap, 256, 0);
+       if (ret < 0)
+               goto aty_init_exit;
 
-       if (register_framebuffer(info) < 0)
+       ret = register_framebuffer(info);
+       if (ret < 0) {
+               fb_dealloc_cmap(&info->cmap);
                goto aty_init_exit;
+       }
 
        fb_list = info;
 
@@ -2695,8 +2669,8 @@ static int __devinit aty_init(struct fb_info *info)
 
 aty_init_exit:
        /* restore video mode */
-       aty_set_crtc(par, &saved_crtc);
-       par->pll_ops->set_pll(info, &saved_pll);
+       aty_set_crtc(par, &par->saved_crtc);
+       par->pll_ops->set_pll(info, &par->saved_pll);
 
 #ifdef CONFIG_MTRR
        if (par->mtrr_reg >= 0) {
@@ -2708,20 +2682,7 @@ aty_init_exit:
            par->mtrr_aper = -1;
        }
 #endif
-       return -1;
-}
-
-static void aty_resume_chip(struct fb_info *info)
-{
-       struct atyfb_par *par = info->par;
-
-       aty_st_le32(MEM_CNTL, par->mem_cntl, par);
-
-       if (par->pll_ops->resume_pll)
-               par->pll_ops->resume_pll(info, &par->pll);
-
-       if (par->aux_start)
-               aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, par) | BUS_APER_REG_DIS, par);
+       return ret;
 }
 
 #ifdef CONFIG_ATARI
@@ -2767,8 +2728,7 @@ static int atyfb_blank(int blank, struct fb_info *info)
        if (par->lock_blank || par->asleep)
                return 0;
 
-#ifdef CONFIG_FB_ATY_BACKLIGHT
-#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
        if (par->lcd_table && blank > FB_BLANK_NORMAL &&
            (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
                u32 pm = aty_ld_lcd(POWER_MANAGEMENT, par);
@@ -2797,8 +2757,7 @@ static int atyfb_blank(int blank, struct fb_info *info)
        }
        aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par);
 
-#ifdef CONFIG_FB_ATY_BACKLIGHT
-#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
        if (par->lcd_table && blank <= FB_BLANK_NORMAL &&
            (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
                u32 pm = aty_ld_lcd(POWER_MANAGEMENT, par);
@@ -2902,8 +2861,6 @@ static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 
 #ifdef __sparc__
 
-extern void (*prom_palette) (int);
-
 static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
                        struct fb_info *info, unsigned long addr)
 {
@@ -2913,10 +2870,6 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
        int node, len, i, j, ret;
        u32 mem, chip_id;
 
-       /* Do not attach when we have a serial console. */
-       if (!con_is_present())
-               return -ENXIO;
-
        /*
         * Map memory-mapped registers.
         */
@@ -3005,7 +2958,7 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
                 * Fix PROMs idea of MEM_CNTL settings...
                 */
                mem = aty_ld_le32(MEM_CNTL, par);
-               chip_id = aty_ld_le32(CONFIG_CHIP_ID, par);
+               chip_id = aty_ld_le32(CNFG_CHIP_ID, par);
                if (((chip_id & CFG_CHIP_TYPE) == VT_CHIP_ID) && !((chip_id >> 24) & 1)) {
                        switch (mem & 0x0f) {
                        case 3:
@@ -3023,7 +2976,7 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
                        default:
                                break;
                        }
-                       if ((aty_ld_le32(CONFIG_STAT0, par) & 7) >= SDRAM)
+                       if ((aty_ld_le32(CNFG_STAT0, par) & 7) >= SDRAM)
                                mem &= ~(0x00700000);
                }
                mem &= ~(0xcf80e000);   /* Turn off all undocumented bits. */
@@ -3395,7 +3348,7 @@ static int __devinit init_from_bios(struct atyfb_par *par)
                PRINTKE("no BIOS frequency table found, use parameters\n");
                ret = -ENXIO;
        }
-       iounmap((void* __iomem )bios_base);
+       iounmap((void __iomem *)bios_base);
 
        return ret;
 }
@@ -3420,7 +3373,7 @@ static int __devinit atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *i
 
        info->fix.mmio_start = raddr;
        par->ati_regbase = ioremap(info->fix.mmio_start, 0x1000);
-       if (par->ati_regbase == 0)
+       if (par->ati_regbase == NULL)
                return -ENOMEM;
 
        info->fix.mmio_start += par->aux_start ? 0x400 : 0xc00;
@@ -3482,14 +3435,7 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi
        struct fb_info *info;
        struct resource *rp;
        struct atyfb_par *par;
-       int i, rc = -ENOMEM;
-
-       for (i = ARRAY_SIZE(aty_chips) - 1; i >= 0; i--)
-               if (pdev->device == aty_chips[i].pci_id)
-                       break;
-
-       if (i < 0)
-               return -ENODEV;
+       int rc = -ENOMEM;
 
        /* Enable device in PCI config */
        if (pci_enable_device(pdev)) {
@@ -3520,7 +3466,7 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi
        par = info->par;
        info->fix = atyfb_fix;
        info->device = &pdev->dev;
-       par->pci_id = aty_chips[i].pci_id;
+       par->pci_id = pdev->device;
        par->res_start = res_start;
        par->res_size = res_size;
        par->irq = pdev->irq;
@@ -3538,13 +3484,11 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi
        pci_set_drvdata(pdev, info);
 
        /* Init chip & register framebuffer */
-       if (aty_init(info))
+       rc = aty_init(info);
+       if (rc)
                goto err_release_io;
 
 #ifdef __sparc__
-       if (!prom_palette)
-               prom_palette = atyfb_palette;
-
        /*
         * Add /dev/fb mmap values.
         */
@@ -3560,6 +3504,11 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi
        par->mmap_map[1].prot_flag = _PAGE_E;
 #endif /* __sparc__ */
 
+       mutex_lock(&reboot_lock);
+       if (!reboot_info)
+               reboot_info = info;
+       mutex_unlock(&reboot_lock);
+
        return 0;
 
 err_release_io:
@@ -3640,7 +3589,7 @@ static int __init atyfb_atari_probe(void)
                }
 
                /* Fake pci_id for correct_chipset() */
-               switch (aty_ld_le32(CONFIG_CHIP_ID, par) & CFG_CHIP_TYPE) {
+               switch (aty_ld_le32(CNFG_CHIP_ID, par) & CFG_CHIP_TYPE) {
                case 0x00d7:
                        par->pci_id = PCI_CHIP_MACH64GX;
                        break;
@@ -3672,8 +3621,8 @@ static void __devexit atyfb_remove(struct fb_info *info)
        struct atyfb_par *par = (struct atyfb_par *) info->par;
 
        /* restore video mode */
-       aty_set_crtc(par, &saved_crtc);
-       par->pll_ops->set_pll(info, &saved_pll);
+       aty_set_crtc(par, &par->saved_crtc);
+       par->pll_ops->set_pll(info, &par->saved_pll);
 
        unregister_framebuffer(info);
 
@@ -3719,21 +3668,70 @@ static void __devexit atyfb_pci_remove(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
 
+       mutex_lock(&reboot_lock);
+       if (reboot_info == info)
+               reboot_info = NULL;
+       mutex_unlock(&reboot_lock);
+
        atyfb_remove(info);
 }
 
-/*
- * This driver uses its own matching table. That will be more difficult
- * to fix, so for now, we just match against any ATI ID and let the
- * probe() function find out what's up. That also mean we don't have
- * a module ID table though.
- */
 static struct pci_device_id atyfb_pci_tbl[] = {
-       { PCI_VENDOR_ID_ATI, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
-         PCI_BASE_CLASS_DISPLAY << 16, 0xff0000, 0 },
-       { 0, }
+#ifdef CONFIG_FB_ATY_GX
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GX) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64CX) },
+#endif /* CONFIG_FB_ATY_GX */
+
+#ifdef CONFIG_FB_ATY_CT
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64CT) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64ET) },
+
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LT) },
+
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64VT) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GT) },
+
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64VU) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GU) },
+
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LG) },
+
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64VV) },
+
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GV) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GW) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GY) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GZ) },
+
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GB) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GD) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GI) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GP) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GQ) },
+
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LB) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LD) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LI) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LP) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LQ) },
+
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GM) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GN) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GO) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GL) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GR) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GS) },
+
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LM) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LN) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LR) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LS) },
+#endif /* CONFIG_FB_ATY_CT */
+       { }
 };
 
+MODULE_DEVICE_TABLE(pci, atyfb_pci_tbl);
+
 static struct pci_driver atyfb_driver = {
        .name           = "atyfb",
        .id_table       = atyfb_pci_tbl,
@@ -3822,6 +3820,56 @@ static int __init atyfb_setup(char *options)
 }
 #endif  /*  MODULE  */
 
+static int atyfb_reboot_notify(struct notifier_block *nb,
+                              unsigned long code, void *unused)
+{
+       struct atyfb_par *par;
+
+       if (code != SYS_RESTART)
+               return NOTIFY_DONE;
+
+       mutex_lock(&reboot_lock);
+
+       if (!reboot_info)
+               goto out;
+
+       if (!lock_fb_info(reboot_info))
+               goto out;
+
+       par = reboot_info->par;
+
+       /*
+        * HP OmniBook 500's BIOS doesn't like the state of the
+        * hardware after atyfb has been used. Restore the hardware
+        * to the original state to allow successful reboots.
+        */
+       aty_set_crtc(par, &par->saved_crtc);
+       par->pll_ops->set_pll(reboot_info, &par->saved_pll);
+
+       unlock_fb_info(reboot_info);
+ out:
+       mutex_unlock(&reboot_lock);
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block atyfb_reboot_notifier = {
+       .notifier_call = atyfb_reboot_notify,
+};
+
+static const struct dmi_system_id atyfb_reboot_ids[] = {
+       {
+               .ident = "HP OmniBook 500",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "HP OmniBook PC"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "HP OmniBook 500 FA"),
+               },
+       },
+
+       { }
+};
+
 static int __init atyfb_init(void)
 {
     int err1 = 1, err2 = 1;
@@ -3840,11 +3888,20 @@ static int __init atyfb_init(void)
     err2 = atyfb_atari_probe();
 #endif
 
-    return (err1 && err2) ? -ENODEV : 0;
+    if (err1 && err2)
+       return -ENODEV;
+
+    if (dmi_check_system(atyfb_reboot_ids))
+       register_reboot_notifier(&atyfb_reboot_notifier);
+
+    return 0;
 }
 
 static void __exit atyfb_exit(void)
 {
+       if (dmi_check_system(atyfb_reboot_ids))
+               unregister_reboot_notifier(&atyfb_reboot_notifier);
+
 #ifdef CONFIG_PCI
        pci_unregister_driver(&atyfb_driver);
 #endif