[PATCH] nvidiafb: Add support for Geforce4 MX 4000
[deliverable/linux.git] / drivers / video / nvidia / nvidia.c
index 96d51144094aecf8471201642993122061f1d96a..a7c4e5e8ead63781420bdb9d0a8c203d8f97a915 100644 (file)
@@ -138,6 +138,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 +286,16 @@ 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, 0x0252,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {PCI_VENDOR_ID_NVIDIA, 0x0313,
@@ -411,12 +423,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
@@ -484,7 +498,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;
@@ -1026,10 +1040,19 @@ 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;
 
@@ -1291,7 +1314,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);
 
@@ -1372,36 +1395,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);
 
+       switch (bpp) {
+       case 0 ... 8:
+               bpp = 8;
+               break;
+       case 9 ... 16:
+               bpp = 16;
+               break;
+       default:
+               bpp = 32;
+               break;
+       }
+
        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);
-               nvidiafb_default_var.bits_per_pixel = 8;
+               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, 8);
+                            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) ?
@@ -1423,7 +1446,7 @@ static int __devinit nvidia_set_fbinfo(struct fb_info *info)
        info->pixmap.flags = FB_PIXMAP_SYSTEM;
 
        if (!hwcur)
-           info->fbops->fb_cursor = soft_cursor;
+           info->fbops->fb_cursor = NULL;
 
        info->var.accel_flags = (!noaccel);
 
@@ -1450,11 +1473,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 */
@@ -1487,6 +1533,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 */
@@ -1515,7 +1563,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);
@@ -1535,22 +1583,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);
-
-       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);
@@ -1572,7 +1608,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;
@@ -1583,10 +1631,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;
@@ -1642,21 +1695,22 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
        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;
 }
 
@@ -1729,6 +1783,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;
        }
@@ -1775,7 +1833,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) "
@@ -1800,6 +1862,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) "
This page took 0.028689 seconds and 5 git commands to generate.