Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / video / nvidia / nvidia.c
index 47733f5..093ab99 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/console.h>
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
 #endif
@@ -29,6 +30,7 @@
 #include <asm/pci-bridge.h>
 #endif
 #ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/machdep.h>
 #include <asm/backlight.h>
 #endif
 
@@ -138,6 +140,8 @@ static struct pci_device_id nvidiafb_pci_tbl[] = {
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420_8X,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_4000,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_448_GO,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_488_GO,
@@ -284,6 +288,18 @@ static struct pci_device_id nvidiafb_pci_tbl[] = {
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6200,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_ALT1,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT1,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT2,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6200_ALT1,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_GT,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_QUADRO_NVS280,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {PCI_VENDOR_ID_NVIDIA, 0x0252,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {PCI_VENDOR_ID_NVIDIA, 0x0313,
@@ -384,6 +400,14 @@ static struct pci_device_id nvidiafb_pci_tbl[] = {
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_GT,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GT,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GTX,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800_GTX,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {PCI_VENDOR_ID_NVIDIA, 0x021d,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {PCI_VENDOR_ID_NVIDIA, 0x021e,
@@ -403,12 +427,14 @@ MODULE_DEVICE_TABLE(pci, nvidiafb_pci_tbl);
 
 /* command line data, set in nvidiafb_setup() */
 static int flatpanel __devinitdata = -1;       /* Autodetect later */
+static int fpdither __devinitdata = -1;
 static int forceCRTC __devinitdata = -1;
 static int hwcur __devinitdata = 0;
 static int noaccel __devinitdata = 0;
 static int noscale __devinitdata = 0;
 static int paneltweak __devinitdata = 0;
 static int vram __devinitdata = 0;
+static int bpp __devinitdata = 8;
 #ifdef CONFIG_MTRR
 static int nomtrr __devinitdata = 0;
 #endif
@@ -476,7 +502,7 @@ static int nvidia_backlight_levels[] = {
 
 static int nvidia_set_backlight_enable(int on, int level, void *data)
 {
-       struct nvidia_par *par = (struct nvidia_par *)data;
+       struct nvidia_par *par = data;
        u32 tmp_pcrt, tmp_pmc, fpcontrol;
 
        tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
@@ -516,9 +542,9 @@ static struct backlight_controller nvidia_backlight_controller = {
 static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8,
                                       u16 bg, u16 fg, u32 w, u32 h)
 {
+       u32 *data = (u32 *) data8;
        int i, j, k = 0;
        u32 b, tmp;
-       u32 *data = (u32 *) data8;
 
        w = (w + 1) & ~1;
 
@@ -593,6 +619,30 @@ static int nvidia_panel_tweak(struct nvidia_par *par,
    return tweak;
 }
 
+static void nvidia_vga_protect(struct nvidia_par *par, int on)
+{
+       unsigned char tmp;
+
+       if (on) {
+               /*
+                * Turn off screen and disable sequencer.
+                */
+               tmp = NVReadSeq(par, 0x01);
+
+               NVWriteSeq(par, 0x00, 0x01);            /* Synchronous Reset */
+               NVWriteSeq(par, 0x01, tmp | 0x20);      /* disable the display */
+       } else {
+               /*
+                * Reenable sequencer, then turn on screen.
+                */
+
+               tmp = NVReadSeq(par, 0x01);
+
+               NVWriteSeq(par, 0x01, tmp & ~0x20);     /* reenable display */
+               NVWriteSeq(par, 0x00, 0x03);            /* End Reset */
+       }
+}
+
 static void nvidia_save_vga(struct nvidia_par *par,
                            struct _riva_hw_state *state)
 {
@@ -619,38 +669,56 @@ static void nvidia_save_vga(struct nvidia_par *par,
        NVTRACE_LEAVE();
 }
 
-static void nvidia_write_regs(struct nvidia_par *par)
+#undef DUMP_REG
+
+static void nvidia_write_regs(struct nvidia_par *par,
+                             struct _riva_hw_state *state)
 {
-       struct _riva_hw_state *state = &par->ModeReg;
        int i;
 
        NVTRACE_ENTER();
-       NVWriteCrtc(par, 0x11, 0x00);
-
-       NVLockUnlock(par, 0);
 
        NVLoadStateExt(par, state);
 
        NVWriteMiscOut(par, state->misc_output);
 
+       for (i = 1; i < NUM_SEQ_REGS; i++) {
+#ifdef DUMP_REG
+               printk(" SEQ[%02x] = %08x\n", i, state->seq[i]);
+#endif
+               NVWriteSeq(par, i, state->seq[i]);
+       }
+
+       /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 of CRTC[17] */
+       NVWriteCrtc(par, 0x11, state->crtc[0x11] & ~0x80);
+
        for (i = 0; i < NUM_CRT_REGS; i++) {
                switch (i) {
                case 0x19:
                case 0x20 ... 0x40:
                        break;
                default:
+#ifdef DUMP_REG
+                       printk("CRTC[%02x] = %08x\n", i, state->crtc[i]);
+#endif
                        NVWriteCrtc(par, i, state->crtc[i]);
                }
        }
 
-       for (i = 0; i < NUM_ATC_REGS; i++)
-               NVWriteAttr(par, i, state->attr[i]);
-
-       for (i = 0; i < NUM_GRC_REGS; i++)
+       for (i = 0; i < NUM_GRC_REGS; i++) {
+#ifdef DUMP_REG
+               printk(" GRA[%02x] = %08x\n", i, state->gra[i]);
+#endif
                NVWriteGr(par, i, state->gra[i]);
+       }
+
+       for (i = 0; i < NUM_ATC_REGS; i++) {
+#ifdef DUMP_REG
+               printk("ATTR[%02x] = %08x\n", i, state->attr[i]);
+#endif
+               NVWriteAttr(par, i, state->attr[i]);
+       }
 
-       for (i = 0; i < NUM_SEQ_REGS; i++)
-               NVWriteSeq(par, i, state->seq[i]);
        NVTRACE_LEAVE();
 }
 
@@ -658,7 +726,7 @@ static int nvidia_calc_regs(struct fb_info *info)
 {
        struct nvidia_par *par = info->par;
        struct _riva_hw_state *state = &par->ModeReg;
-       int i, depth = fb_get_color_depth(&info->var);
+       int i, depth = fb_get_color_depth(&info->var, &info->fix);
        int h_display = info->var.xres / 8 - 1;
        int h_start = (info->var.xres + info->var.right_margin) / 8 - 1;
        int h_end = (info->var.xres + info->var.right_margin +
@@ -860,7 +928,7 @@ static void nvidia_init_vga(struct fb_info *info)
        for (i = 0; i < 0x10; i++)
                state->attr[i] = i;
        state->attr[0x10] = 0x41;
-       state->attr[0x11] = 0x01;
+       state->attr[0x11] = 0xff;
        state->attr[0x12] = 0x0f;
        state->attr[0x13] = 0x00;
        state->attr[0x14] = 0x00;
@@ -890,11 +958,11 @@ static int nvidiafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
        struct nvidia_par *par = info->par;
        u8 data[MAX_CURS * MAX_CURS / 8];
-       u16 fg, bg;
        int i, set = cursor->set;
+       u16 fg, bg;
 
        if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS)
-               return soft_cursor(info, cursor);
+               return -ENXIO;
 
        NVShowHideCursor(par, 0);
 
@@ -931,21 +999,18 @@ static int nvidiafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
                if (src) {
                        switch (cursor->rop) {
                        case ROP_XOR:
-                               for (i = 0; i < s_pitch * cursor->image.height;
-                                    i++)
+                               for (i = 0; i < s_pitch * cursor->image.height; i++)
                                        src[i] = dat[i] ^ msk[i];
                                break;
                        case ROP_COPY:
                        default:
-                               for (i = 0; i < s_pitch * cursor->image.height;
-                                    i++)
+                               for (i = 0; i < s_pitch * cursor->image.height; i++)
                                        src[i] = dat[i] & msk[i];
                                break;
                        }
 
-                       fb_sysmove_buf_aligned(info, &info->pixmap, data,
-                                              d_pitch, src, s_pitch,
-                                              cursor->image.height);
+                       fb_pad_aligned_buffer(data, d_pitch, src, s_pitch,
+                                               cursor->image.height);
 
                        bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) |
                            ((info->cmap.green[bg_idx] & 0xf8) << 2) |
@@ -977,13 +1042,24 @@ static int nvidiafb_set_par(struct fb_info *info)
        NVTRACE_ENTER();
 
        NVLockUnlock(par, 1);
-       if (!par->FlatPanel || (info->var.bits_per_pixel != 24) ||
-           !par->twoHeads)
+       if (!par->FlatPanel || !par->twoHeads)
                par->FPDither = 0;
 
+       if (par->FPDither < 0) {
+               if ((par->Chipset & 0x0ff0) == 0x0110)
+                       par->FPDither = !!(NV_RD32(par->PRAMDAC, 0x0528)
+                                          & 0x00010000);
+               else
+                       par->FPDither = !!(NV_RD32(par->PRAMDAC, 0x083C) & 1);
+               printk(KERN_INFO PFX "Flat panel dithering %s\n",
+                      par->FPDither ? "enabled" : "disabled");
+       }
+
+       info->fix.visual = (info->var.bits_per_pixel == 8) ?
+           FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+
        nvidia_init_vga(info);
        nvidia_calc_regs(info);
-       nvidia_write_regs(par);
 
        NVLockUnlock(par, 0);
        if (par->twoHeads) {
@@ -992,12 +1068,25 @@ static int nvidiafb_set_par(struct fb_info *info)
                NVLockUnlock(par, 0);
        }
 
-       NVWriteCrtc(par, 0x11, 0x00);
+       nvidia_vga_protect(par, 1);
+
+       nvidia_write_regs(par, &par->ModeReg);
+       NVSetStartAddress(par, 0);
+
+#if defined (__BIG_ENDIAN)
+       /* turn on LFB swapping */
+       {
+               unsigned char tmp;
+
+               VGA_WR08(par->PCIO, 0x3d4, 0x46);
+               tmp = VGA_RD08(par->PCIO, 0x3d5);
+               tmp |= (1 << 7);
+               VGA_WR08(par->PCIO, 0x3d5, tmp);
+    }
+#endif
+
        info->fix.line_length = (info->var.xres_virtual *
                                 info->var.bits_per_pixel) >> 3;
-       info->fix.visual = (info->var.bits_per_pixel == 8) ?
-           FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
-
        if (info->var.accel_flags) {
                info->fbops->fb_imageblit = nvidiafb_imageblit;
                info->fbops->fb_fillrect = nvidiafb_fillrect;
@@ -1017,7 +1106,7 @@ static int nvidiafb_set_par(struct fb_info *info)
 
        par->cursor_reset = 1;
 
-       NVWriteCrtc(par, 0x11, 0xff);
+       nvidia_vga_protect(par, 0);
 
        NVTRACE_LEAVE();
        return 0;
@@ -1228,7 +1317,7 @@ static int nvidiafb_pan_display(struct fb_var_screeninfo *var,
        struct nvidia_par *par = info->par;
        u32 total;
 
-       total = info->var.yoffset * info->fix.line_length + info->var.xoffset;
+       total = var->yoffset * info->fix.line_length + var->xoffset;
 
        NVSetStartAddress(par, total);
 
@@ -1267,7 +1356,7 @@ static int nvidiafb_blank(int blank, struct fb_info *info)
        NVWriteCrtc(par, 0x1a, vesa);
 
 #ifdef CONFIG_PMAC_BACKLIGHT
-       if (par->FlatPanel && _machine == _MACH_Pmac) {
+       if (par->FlatPanel && machine_is(powermac)) {
                set_backlight_enable(!blank);
        }
 #endif
@@ -1291,6 +1380,57 @@ static struct fb_ops nvidia_fb_ops = {
        .fb_sync        = nvidiafb_sync,
 };
 
+#ifdef CONFIG_PM
+static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t state)
+{
+       struct fb_info *info = pci_get_drvdata(dev);
+       struct nvidia_par *par = info->par;
+
+       acquire_console_sem();
+       par->pm_state = state.event;
+
+       if (state.event == PM_EVENT_FREEZE) {
+               dev->dev.power.power_state = state;
+       } else {
+               fb_set_suspend(info, 1);
+               nvidiafb_blank(FB_BLANK_POWERDOWN, info);
+               nvidia_write_regs(par, &par->SavedReg);
+               pci_save_state(dev);
+               pci_disable_device(dev);
+               pci_set_power_state(dev, pci_choose_state(dev, state));
+       }
+
+       release_console_sem();
+       return 0;
+}
+
+static int nvidiafb_resume(struct pci_dev *dev)
+{
+       struct fb_info *info = pci_get_drvdata(dev);
+       struct nvidia_par *par = info->par;
+
+       acquire_console_sem();
+       pci_set_power_state(dev, PCI_D0);
+
+       if (par->pm_state != PM_EVENT_FREEZE) {
+               pci_restore_state(dev);
+               pci_enable_device(dev);
+               pci_set_master(dev);
+       }
+
+       par->pm_state = PM_EVENT_ON;
+       nvidiafb_set_par(info);
+       fb_set_suspend (info, 0);
+       nvidiafb_blank(FB_BLANK_UNBLANK, info);
+
+       release_console_sem();
+       return 0;
+}
+#else
+#define nvidiafb_suspend NULL
+#define nvidiafb_resume NULL
+#endif
+
 static int __devinit nvidia_set_fbinfo(struct fb_info *info)
 {
        struct fb_monspecs *specs = &info->monspecs;
@@ -1309,29 +1449,36 @@ static int __devinit nvidia_set_fbinfo(struct fb_info *info)
                                 info->monspecs.modedb_len, &info->modelist);
        fb_var_to_videomode(&modedb, &nvidiafb_default_var);
 
-       if (specs->modedb != NULL) {
-               /* get preferred timing */
-               if (specs->misc & FB_MISC_1ST_DETAIL) {
-                       int i;
-
-                       for (i = 0; i < specs->modedb_len; i++) {
-                               if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
-                                       modedb = specs->modedb[i];
-                                       break;
-                               }
-                       }
-               } else {
-                       /* otherwise, get first mode in database */
-                       modedb = specs->modedb[0];
-               }
+       switch (bpp) {
+       case 0 ... 8:
+               bpp = 8;
+               break;
+       case 9 ... 16:
+               bpp = 16;
+               break;
+       default:
+               bpp = 32;
+               break;
+       }
 
-               fb_videomode_to_var(&nvidiafb_default_var, &modedb);
-               nvidiafb_default_var.bits_per_pixel = 8;
+       if (specs->modedb != NULL) {
+               struct fb_videomode *modedb;
+
+               modedb = fb_find_best_display(specs, &info->modelist);
+               fb_videomode_to_var(&nvidiafb_default_var, modedb);
+               nvidiafb_default_var.bits_per_pixel = bpp;
+       } else if (par->fpWidth && par->fpHeight) {
+               char buf[16];
+
+               memset(buf, 0, 16);
+               snprintf(buf, 15, "%dx%dMR", par->fpWidth, par->fpHeight);
+               fb_find_mode(&nvidiafb_default_var, info, buf, specs->modedb,
+                            specs->modedb_len, &modedb, bpp);
        }
 
        if (mode_option)
                fb_find_mode(&nvidiafb_default_var, info, mode_option,
-                            specs->modedb, specs->modedb_len, &modedb, 8);
+                            specs->modedb, specs->modedb_len, &modedb, bpp);
 
        info->var = nvidiafb_default_var;
        info->fix.visual = (info->var.bits_per_pixel == 8) ?
@@ -1348,11 +1495,13 @@ static int __devinit nvidia_set_fbinfo(struct fb_info *info)
 
        info->pixmap.scan_align = 4;
        info->pixmap.buf_align = 4;
+       info->pixmap.access_align = 32;
        info->pixmap.size = 8 * 1024;
        info->pixmap.flags = FB_PIXMAP_SYSTEM;
 
        if (!hwcur)
-               info->fbops->fb_cursor = soft_cursor;
+           info->fbops->fb_cursor = NULL;
+
        info->var.accel_flags = (!noaccel);
 
        switch (par->Architecture) {
@@ -1378,11 +1527,34 @@ static int __devinit nvidia_set_fbinfo(struct fb_info *info)
        return nvidiafb_check_var(&info->var, info);
 }
 
-static u32 __devinit nvidia_get_arch(struct pci_dev *pd)
+static u32 __devinit nvidia_get_chipset(struct fb_info *info)
 {
+       struct nvidia_par *par = info->par;
+       u32 id = (par->pci_dev->vendor << 16) | par->pci_dev->device;
+
+       printk("nvidiafb: PCI id - %x\n", id);
+       if ((id & 0xfff0) == 0x00f0) {
+               /* pci-e */
+               printk("nvidiafb: PCI-E card\n");
+               id = NV_RD32(par->REGS, 0x1800);
+
+               if ((id & 0x0000ffff) == 0x000010DE)
+                       id = 0x10DE0000 | (id >> 16);
+               else if ((id & 0xffff0000) == 0xDE100000) /* wrong endian */
+                       id = 0x10DE0000 | ((id << 8) & 0x0000ff00) |
+                            ((id >> 8) & 0x000000ff);
+       }
+
+       printk("nvidiafb: Actual id - %x\n", id);
+       return id;
+}
+
+static u32 __devinit nvidia_get_arch(struct fb_info *info)
+{
+       struct nvidia_par *par = info->par;
        u32 arch = 0;
 
-       switch (pd->device & 0x0ff0) {
+       switch (par->Chipset & 0x0ff0) {
        case 0x0100:            /* GeForce 256 */
        case 0x0110:            /* GeForce2 MX */
        case 0x0150:            /* GeForce2 */
@@ -1415,6 +1587,8 @@ static u32 __devinit nvidia_get_arch(struct pci_dev *pd)
        case 0x0210:
        case 0x0220:
        case 0x0230:
+       case 0x0290:
+       case 0x0390:
                arch = NV_ARCH_40;
                break;
        case 0x0020:            /* TNT, TNT2 */
@@ -1443,7 +1617,7 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
        if (!info)
                goto err_out;
 
-       par = (struct nvidia_par *)info->par;
+       par = info->par;
        par->pci_dev = pd;
 
        info->pixmap.addr = kmalloc(8 * 1024, GFP_KERNEL);
@@ -1463,26 +1637,10 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
                goto err_out_request;
        }
 
-       par->Architecture = nvidia_get_arch(pd);
-
-       par->Chipset = (pd->vendor << 16) | pd->device;
-       printk(KERN_INFO PFX "nVidia device/chipset %X\n", par->Chipset);
-
-#ifdef CONFIG_PCI_NAMES
-       printk(KERN_INFO PFX "%s\n", pd->pretty_name);
-#endif
-
-       if (par->Architecture == 0) {
-               printk(KERN_ERR PFX "unknown NV_ARCH\n");
-               goto err_out_free_base0;
-       }
-
-       sprintf(nvidiafb_fix.id, "NV%x", (pd->device & 0x0ff0) >> 4);
-
        par->FlatPanel = flatpanel;
-
        if (flatpanel == 1)
                printk(KERN_INFO PFX "flatpanel support enabled\n");
+       par->FPDither = fpdither;
 
        par->CRTCnumber = forceCRTC;
        par->FpScale = (!noscale);
@@ -1504,7 +1662,19 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
                goto err_out_free_base0;
        }
 
-       NVCommonSetup(info);
+       par->Chipset = nvidia_get_chipset(info);
+       printk(KERN_INFO PFX "nVidia device/chipset %X\n", par->Chipset);
+       par->Architecture = nvidia_get_arch(info);
+
+       if (par->Architecture == 0) {
+               printk(KERN_ERR PFX "unknown NV_ARCH\n");
+               goto err_out_arch;
+       }
+
+       sprintf(nvidiafb_fix.id, "NV%x", (pd->device & 0x0ff0) >> 4);
+
+       if (NVCommonSetup(info))
+               goto err_out_arch;
 
        par->FbAddress = nvidiafb_fix.smem_start;
        par->FbMapSize = par->RamAmountKBytes * 1024;
@@ -1515,10 +1685,15 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
        if (par->FbMapSize > 64 * 1024 * 1024)
                par->FbMapSize = 64 * 1024 * 1024;
 
-       par->FbUsableSize = par->FbMapSize - (128 * 1024);
+       if(par->Architecture >= NV_ARCH_40)
+               par->FbUsableSize = par->FbMapSize - (560 * 1024);
+       else
+               par->FbUsableSize = par->FbMapSize - (128 * 1024);
        par->ScratchBufferSize = (par->Architecture < NV_ARCH_10) ? 8 * 1024 :
            16 * 1024;
        par->ScratchBufferStart = par->FbUsableSize - par->ScratchBufferSize;
+       par->CursorStart = par->FbUsableSize + (32 * 1024);
+
        info->screen_base = ioremap(nvidiafb_fix.smem_start, par->FbMapSize);
        info->screen_size = par->FbUsableSize;
        nvidiafb_fix.smem_len = par->RamAmountKBytes * 1024;
@@ -1567,28 +1742,29 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
               info->fix.id,
               par->FbMapSize / (1024 * 1024), info->fix.smem_start);
 #ifdef CONFIG_PMAC_BACKLIGHT
-       if (par->FlatPanel && _machine == _MACH_Pmac)
+       if (par->FlatPanel && machine_is(powermac))
                register_backlight_controller(&nvidia_backlight_controller,
                                              par, "mnca");
 #endif
        NVTRACE_LEAVE();
        return 0;
 
-      err_out_iounmap_fb:
+err_out_iounmap_fb:
        iounmap(info->screen_base);
-      err_out_free_base1:
+err_out_free_base1:
        fb_destroy_modedb(info->monspecs.modedb);
        nvidia_delete_i2c_busses(par);
+err_out_arch:
        iounmap(par->REGS);
-      err_out_free_base0:
+err_out_free_base0:
        pci_release_regions(pd);
-      err_out_request:
+err_out_request:
        pci_disable_device(pd);
-      err_out_enable:
+err_out_enable:
        kfree(info->pixmap.addr);
-      err_out_kfree:
+err_out_kfree:
        framebuffer_release(info);
-      err_out:
+err_out:
        return -ENODEV;
 }
 
@@ -1598,8 +1774,6 @@ static void __exit nvidiafb_remove(struct pci_dev *pd)
        struct nvidia_par *par = info->par;
 
        NVTRACE_ENTER();
-       if (!info)
-               return;
 
        unregister_framebuffer(info);
 #ifdef CONFIG_MTRR
@@ -1661,6 +1835,10 @@ static int __devinit nvidiafb_setup(char *options)
                } else if (!strncmp(this_opt, "nomtrr", 6)) {
                        nomtrr = 1;
 #endif
+               } else if (!strncmp(this_opt, "fpdither:", 9)) {
+                       fpdither = simple_strtol(this_opt+9, NULL, 0);
+               } else if (!strncmp(this_opt, "bpp:", 4)) {
+                       bpp = simple_strtoul(this_opt+4, NULL, 0);
                } else
                        mode_option = this_opt;
        }
@@ -1672,8 +1850,10 @@ static int __devinit nvidiafb_setup(char *options)
 static struct pci_driver nvidiafb_driver = {
        .name = "nvidiafb",
        .id_table = nvidiafb_pci_tbl,
-       .probe = nvidiafb_probe,
-       .remove = __exit_p(nvidiafb_remove),
+       .probe    = nvidiafb_probe,
+       .suspend  = nvidiafb_suspend,
+       .resume   = nvidiafb_resume,
+       .remove   = __exit_p(nvidiafb_remove),
 };
 
 /* ------------------------------------------------------------------------- *
@@ -1707,7 +1887,11 @@ module_exit(nvidiafb_exit);
 module_param(flatpanel, int, 0);
 MODULE_PARM_DESC(flatpanel,
                 "Enables experimental flat panel support for some chipsets. "
-                "(0 or 1=enabled) (default=0)");
+                "(0=disabled, 1=enabled, -1=autodetect) (default=-1)");
+module_param(fpdither, int, 0);
+MODULE_PARM_DESC(fpdither,
+                "Enables dithering of flat panel for 6 bits panels. "
+                "(0=disabled, 1=enabled, -1=autodetect) (default=-1)");
 module_param(hwcur, int, 0);
 MODULE_PARM_DESC(hwcur,
                 "Enables hardware cursor implementation. (0 or 1=enabled) "
@@ -1732,6 +1916,11 @@ module_param(vram, int, 0);
 MODULE_PARM_DESC(vram,
                 "amount of framebuffer memory to remap in MiB"
                 "(default=0 - remap entire memory)");
+module_param(mode_option, charp, 0);
+MODULE_PARM_DESC(mode_option, "Specify initial video mode");
+module_param(bpp, int, 0);
+MODULE_PARM_DESC(bpp, "pixel width in bits"
+                "(default=8)");
 #ifdef CONFIG_MTRR
 module_param(nomtrr, bool, 0);
 MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) "