* 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,
*/
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);
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
#endif /* CONFIG_FB_ATY_CT */
};
-/* can not fail */
static int __devinit correct_chipset(struct atyfb_par *par)
{
u8 rev;
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;
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;
#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,
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);
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);
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 &=
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__ */
return timeout ? 0 : -EIO;
}
-#endif
+#endif /* CONFIG_PPC_PMAC */
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);
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);
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);
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;
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);
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];
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)
#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);
}
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;
}
#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 |
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;
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) {
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
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);
}
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);
#ifdef __sparc__
-extern void (*prom_palette) (int);
-
static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
struct fb_info *info, unsigned long addr)
{
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.
*/
* 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:
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. */
PRINTKE("no BIOS frequency table found, use parameters\n");
ret = -ENXIO;
}
- iounmap((void* __iomem )bios_base);
+ iounmap((void __iomem *)bios_base);
return ret;
}
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;
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)) {
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;
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.
*/
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:
}
/* 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;
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);
{
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,
}
#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;
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