]> err.no Git - linux-2.6/blobdiff - drivers/video/nvidia/nvidia.c
Merge master.kernel.org:/home/rmk/linux-2.6-arm
[linux-2.6] / drivers / video / nvidia / nvidia.c
index 3620de0f252e6100c3da6a895de1cf7f3297dc14..0b40a2a721c180609c15b16e82e3209b195a846e 100644 (file)
@@ -384,6 +384,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,6 +411,7 @@ 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;
@@ -619,41 +628,85 @@ static void nvidia_save_vga(struct nvidia_par *par,
        NVTRACE_LEAVE();
 }
 
+#undef DUMP_REG
+
 static void nvidia_write_regs(struct nvidia_par *par)
 {
        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();
 }
 
+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 int nvidia_calc_regs(struct fb_info *info)
 {
        struct nvidia_par *par = info->par;
@@ -860,7 +913,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;
@@ -893,7 +946,7 @@ static int nvidiafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
        int i, set = cursor->set;
        u16 fg, bg;
 
-       if (!hwcur || cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS)
+       if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS)
                return -ENXIO;
 
        NVShowHideCursor(par, 0);
@@ -974,16 +1027,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,7 +1053,22 @@ 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);
+
+#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;
        if (info->var.accel_flags) {
@@ -1014,7 +1090,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;
@@ -1307,22 +1383,10 @@ static int __devinit nvidia_set_fbinfo(struct fb_info *info)
        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];
-               }
+               struct fb_videomode *modedb;
 
-               fb_videomode_to_var(&nvidiafb_default_var, &modedb);
+               modedb = fb_find_best_display(specs, &info->modelist);
+               fb_videomode_to_var(&nvidiafb_default_var, modedb);
                nvidiafb_default_var.bits_per_pixel = 8;
        } else if (par->fpWidth && par->fpHeight) {
                char buf[16];
@@ -1356,6 +1420,9 @@ static int __devinit nvidia_set_fbinfo(struct fb_info *info)
        info->pixmap.size = 8 * 1024;
        info->pixmap.flags = FB_PIXMAP_SYSTEM;
 
+       if (!hwcur)
+           info->fbops->fb_cursor = NULL;
+
        info->var.accel_flags = (!noaccel);
 
        switch (par->Architecture) {
@@ -1479,9 +1546,9 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
        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);
@@ -1660,6 +1727,8 @@ 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
                        mode_option = this_opt;
        }
@@ -1706,7 +1775,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) "