diff options
Diffstat (limited to 'drivers/video/nvidia/nvidia.c')
-rw-r--r-- | drivers/video/nvidia/nvidia.c | 128 |
1 files changed, 95 insertions, 33 deletions
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 308defc389a2..0b40a2a721c1 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c | |||
@@ -411,6 +411,7 @@ MODULE_DEVICE_TABLE(pci, nvidiafb_pci_tbl); | |||
411 | 411 | ||
412 | /* command line data, set in nvidiafb_setup() */ | 412 | /* command line data, set in nvidiafb_setup() */ |
413 | static int flatpanel __devinitdata = -1; /* Autodetect later */ | 413 | static int flatpanel __devinitdata = -1; /* Autodetect later */ |
414 | static int fpdither __devinitdata = -1; | ||
414 | static int forceCRTC __devinitdata = -1; | 415 | static int forceCRTC __devinitdata = -1; |
415 | static int hwcur __devinitdata = 0; | 416 | static int hwcur __devinitdata = 0; |
416 | static int noaccel __devinitdata = 0; | 417 | static int noaccel __devinitdata = 0; |
@@ -627,41 +628,85 @@ static void nvidia_save_vga(struct nvidia_par *par, | |||
627 | NVTRACE_LEAVE(); | 628 | NVTRACE_LEAVE(); |
628 | } | 629 | } |
629 | 630 | ||
631 | #undef DUMP_REG | ||
632 | |||
630 | static void nvidia_write_regs(struct nvidia_par *par) | 633 | static void nvidia_write_regs(struct nvidia_par *par) |
631 | { | 634 | { |
632 | struct _riva_hw_state *state = &par->ModeReg; | 635 | struct _riva_hw_state *state = &par->ModeReg; |
633 | int i; | 636 | int i; |
634 | 637 | ||
635 | NVTRACE_ENTER(); | 638 | NVTRACE_ENTER(); |
636 | NVWriteCrtc(par, 0x11, 0x00); | ||
637 | |||
638 | NVLockUnlock(par, 0); | ||
639 | 639 | ||
640 | NVLoadStateExt(par, state); | 640 | NVLoadStateExt(par, state); |
641 | 641 | ||
642 | NVWriteMiscOut(par, state->misc_output); | 642 | NVWriteMiscOut(par, state->misc_output); |
643 | 643 | ||
644 | for (i = 1; i < NUM_SEQ_REGS; i++) { | ||
645 | #ifdef DUMP_REG | ||
646 | printk(" SEQ[%02x] = %08x\n", i, state->seq[i]); | ||
647 | #endif | ||
648 | NVWriteSeq(par, i, state->seq[i]); | ||
649 | } | ||
650 | |||
651 | /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 of CRTC[17] */ | ||
652 | NVWriteCrtc(par, 0x11, state->crtc[0x11] & ~0x80); | ||
653 | |||
644 | for (i = 0; i < NUM_CRT_REGS; i++) { | 654 | for (i = 0; i < NUM_CRT_REGS; i++) { |
645 | switch (i) { | 655 | switch (i) { |
646 | case 0x19: | 656 | case 0x19: |
647 | case 0x20 ... 0x40: | 657 | case 0x20 ... 0x40: |
648 | break; | 658 | break; |
649 | default: | 659 | default: |
660 | #ifdef DUMP_REG | ||
661 | printk("CRTC[%02x] = %08x\n", i, state->crtc[i]); | ||
662 | #endif | ||
650 | NVWriteCrtc(par, i, state->crtc[i]); | 663 | NVWriteCrtc(par, i, state->crtc[i]); |
651 | } | 664 | } |
652 | } | 665 | } |
653 | 666 | ||
654 | for (i = 0; i < NUM_ATC_REGS; i++) | 667 | for (i = 0; i < NUM_GRC_REGS; i++) { |
655 | NVWriteAttr(par, i, state->attr[i]); | 668 | #ifdef DUMP_REG |
656 | 669 | printk(" GRA[%02x] = %08x\n", i, state->gra[i]); | |
657 | for (i = 0; i < NUM_GRC_REGS; i++) | 670 | #endif |
658 | NVWriteGr(par, i, state->gra[i]); | 671 | NVWriteGr(par, i, state->gra[i]); |
672 | } | ||
673 | |||
674 | for (i = 0; i < NUM_ATC_REGS; i++) { | ||
675 | #ifdef DUMP_REG | ||
676 | printk("ATTR[%02x] = %08x\n", i, state->attr[i]); | ||
677 | #endif | ||
678 | NVWriteAttr(par, i, state->attr[i]); | ||
679 | } | ||
659 | 680 | ||
660 | for (i = 0; i < NUM_SEQ_REGS; i++) | ||
661 | NVWriteSeq(par, i, state->seq[i]); | ||
662 | NVTRACE_LEAVE(); | 681 | NVTRACE_LEAVE(); |
663 | } | 682 | } |
664 | 683 | ||
684 | static void nvidia_vga_protect(struct nvidia_par *par, int on) | ||
685 | { | ||
686 | unsigned char tmp; | ||
687 | |||
688 | if (on) { | ||
689 | /* | ||
690 | * Turn off screen and disable sequencer. | ||
691 | */ | ||
692 | tmp = NVReadSeq(par, 0x01); | ||
693 | |||
694 | NVWriteSeq(par, 0x00, 0x01); /* Synchronous Reset */ | ||
695 | NVWriteSeq(par, 0x01, tmp | 0x20); /* disable the display */ | ||
696 | } else { | ||
697 | /* | ||
698 | * Reenable sequencer, then turn on screen. | ||
699 | */ | ||
700 | |||
701 | tmp = NVReadSeq(par, 0x01); | ||
702 | |||
703 | NVWriteSeq(par, 0x01, tmp & ~0x20); /* reenable display */ | ||
704 | NVWriteSeq(par, 0x00, 0x03); /* End Reset */ | ||
705 | } | ||
706 | } | ||
707 | |||
708 | |||
709 | |||
665 | static int nvidia_calc_regs(struct fb_info *info) | 710 | static int nvidia_calc_regs(struct fb_info *info) |
666 | { | 711 | { |
667 | struct nvidia_par *par = info->par; | 712 | struct nvidia_par *par = info->par; |
@@ -868,7 +913,7 @@ static void nvidia_init_vga(struct fb_info *info) | |||
868 | for (i = 0; i < 0x10; i++) | 913 | for (i = 0; i < 0x10; i++) |
869 | state->attr[i] = i; | 914 | state->attr[i] = i; |
870 | state->attr[0x10] = 0x41; | 915 | state->attr[0x10] = 0x41; |
871 | state->attr[0x11] = 0x01; | 916 | state->attr[0x11] = 0xff; |
872 | state->attr[0x12] = 0x0f; | 917 | state->attr[0x12] = 0x0f; |
873 | state->attr[0x13] = 0x00; | 918 | state->attr[0x13] = 0x00; |
874 | state->attr[0x14] = 0x00; | 919 | state->attr[0x14] = 0x00; |
@@ -982,16 +1027,24 @@ static int nvidiafb_set_par(struct fb_info *info) | |||
982 | NVTRACE_ENTER(); | 1027 | NVTRACE_ENTER(); |
983 | 1028 | ||
984 | NVLockUnlock(par, 1); | 1029 | NVLockUnlock(par, 1); |
985 | if (!par->FlatPanel || (info->var.bits_per_pixel != 24) || | 1030 | if (!par->FlatPanel || !par->twoHeads) |
986 | !par->twoHeads) | ||
987 | par->FPDither = 0; | 1031 | par->FPDither = 0; |
988 | 1032 | ||
1033 | if (par->FPDither < 0) { | ||
1034 | if ((par->Chipset & 0x0ff0) == 0x0110) | ||
1035 | par->FPDither = !!(NV_RD32(par->PRAMDAC, 0x0528) | ||
1036 | & 0x00010000); | ||
1037 | else | ||
1038 | par->FPDither = !!(NV_RD32(par->PRAMDAC, 0x083C) & 1); | ||
1039 | printk(KERN_INFO PFX "Flat panel dithering %s\n", | ||
1040 | par->FPDither ? "enabled" : "disabled"); | ||
1041 | } | ||
1042 | |||
989 | info->fix.visual = (info->var.bits_per_pixel == 8) ? | 1043 | info->fix.visual = (info->var.bits_per_pixel == 8) ? |
990 | FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; | 1044 | FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; |
991 | 1045 | ||
992 | nvidia_init_vga(info); | 1046 | nvidia_init_vga(info); |
993 | nvidia_calc_regs(info); | 1047 | nvidia_calc_regs(info); |
994 | nvidia_write_regs(par); | ||
995 | 1048 | ||
996 | NVLockUnlock(par, 0); | 1049 | NVLockUnlock(par, 0); |
997 | if (par->twoHeads) { | 1050 | if (par->twoHeads) { |
@@ -1000,7 +1053,22 @@ static int nvidiafb_set_par(struct fb_info *info) | |||
1000 | NVLockUnlock(par, 0); | 1053 | NVLockUnlock(par, 0); |
1001 | } | 1054 | } |
1002 | 1055 | ||
1003 | NVWriteCrtc(par, 0x11, 0x00); | 1056 | nvidia_vga_protect(par, 1); |
1057 | |||
1058 | nvidia_write_regs(par); | ||
1059 | |||
1060 | #if defined (__BIG_ENDIAN) | ||
1061 | /* turn on LFB swapping */ | ||
1062 | { | ||
1063 | unsigned char tmp; | ||
1064 | |||
1065 | VGA_WR08(par->PCIO, 0x3d4, 0x46); | ||
1066 | tmp = VGA_RD08(par->PCIO, 0x3d5); | ||
1067 | tmp |= (1 << 7); | ||
1068 | VGA_WR08(par->PCIO, 0x3d5, tmp); | ||
1069 | } | ||
1070 | #endif | ||
1071 | |||
1004 | info->fix.line_length = (info->var.xres_virtual * | 1072 | info->fix.line_length = (info->var.xres_virtual * |
1005 | info->var.bits_per_pixel) >> 3; | 1073 | info->var.bits_per_pixel) >> 3; |
1006 | if (info->var.accel_flags) { | 1074 | if (info->var.accel_flags) { |
@@ -1022,7 +1090,7 @@ static int nvidiafb_set_par(struct fb_info *info) | |||
1022 | 1090 | ||
1023 | par->cursor_reset = 1; | 1091 | par->cursor_reset = 1; |
1024 | 1092 | ||
1025 | NVWriteCrtc(par, 0x11, 0xff); | 1093 | nvidia_vga_protect(par, 0); |
1026 | 1094 | ||
1027 | NVTRACE_LEAVE(); | 1095 | NVTRACE_LEAVE(); |
1028 | return 0; | 1096 | return 0; |
@@ -1315,22 +1383,10 @@ static int __devinit nvidia_set_fbinfo(struct fb_info *info) | |||
1315 | fb_var_to_videomode(&modedb, &nvidiafb_default_var); | 1383 | fb_var_to_videomode(&modedb, &nvidiafb_default_var); |
1316 | 1384 | ||
1317 | if (specs->modedb != NULL) { | 1385 | if (specs->modedb != NULL) { |
1318 | /* get preferred timing */ | 1386 | struct fb_videomode *modedb; |
1319 | if (specs->misc & FB_MISC_1ST_DETAIL) { | ||
1320 | int i; | ||
1321 | |||
1322 | for (i = 0; i < specs->modedb_len; i++) { | ||
1323 | if (specs->modedb[i].flag & FB_MODE_IS_FIRST) { | ||
1324 | modedb = specs->modedb[i]; | ||
1325 | break; | ||
1326 | } | ||
1327 | } | ||
1328 | } else { | ||
1329 | /* otherwise, get first mode in database */ | ||
1330 | modedb = specs->modedb[0]; | ||
1331 | } | ||
1332 | 1387 | ||
1333 | fb_videomode_to_var(&nvidiafb_default_var, &modedb); | 1388 | modedb = fb_find_best_display(specs, &info->modelist); |
1389 | fb_videomode_to_var(&nvidiafb_default_var, modedb); | ||
1334 | nvidiafb_default_var.bits_per_pixel = 8; | 1390 | nvidiafb_default_var.bits_per_pixel = 8; |
1335 | } else if (par->fpWidth && par->fpHeight) { | 1391 | } else if (par->fpWidth && par->fpHeight) { |
1336 | char buf[16]; | 1392 | char buf[16]; |
@@ -1365,7 +1421,7 @@ static int __devinit nvidia_set_fbinfo(struct fb_info *info) | |||
1365 | info->pixmap.flags = FB_PIXMAP_SYSTEM; | 1421 | info->pixmap.flags = FB_PIXMAP_SYSTEM; |
1366 | 1422 | ||
1367 | if (!hwcur) | 1423 | if (!hwcur) |
1368 | info->fbops->fb_cursor = soft_cursor; | 1424 | info->fbops->fb_cursor = NULL; |
1369 | 1425 | ||
1370 | info->var.accel_flags = (!noaccel); | 1426 | info->var.accel_flags = (!noaccel); |
1371 | 1427 | ||
@@ -1490,9 +1546,9 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd, | |||
1490 | sprintf(nvidiafb_fix.id, "NV%x", (pd->device & 0x0ff0) >> 4); | 1546 | sprintf(nvidiafb_fix.id, "NV%x", (pd->device & 0x0ff0) >> 4); |
1491 | 1547 | ||
1492 | par->FlatPanel = flatpanel; | 1548 | par->FlatPanel = flatpanel; |
1493 | |||
1494 | if (flatpanel == 1) | 1549 | if (flatpanel == 1) |
1495 | printk(KERN_INFO PFX "flatpanel support enabled\n"); | 1550 | printk(KERN_INFO PFX "flatpanel support enabled\n"); |
1551 | par->FPDither = fpdither; | ||
1496 | 1552 | ||
1497 | par->CRTCnumber = forceCRTC; | 1553 | par->CRTCnumber = forceCRTC; |
1498 | par->FpScale = (!noscale); | 1554 | par->FpScale = (!noscale); |
@@ -1671,6 +1727,8 @@ static int __devinit nvidiafb_setup(char *options) | |||
1671 | } else if (!strncmp(this_opt, "nomtrr", 6)) { | 1727 | } else if (!strncmp(this_opt, "nomtrr", 6)) { |
1672 | nomtrr = 1; | 1728 | nomtrr = 1; |
1673 | #endif | 1729 | #endif |
1730 | } else if (!strncmp(this_opt, "fpdither:", 9)) { | ||
1731 | fpdither = simple_strtol(this_opt+9, NULL, 0); | ||
1674 | } else | 1732 | } else |
1675 | mode_option = this_opt; | 1733 | mode_option = this_opt; |
1676 | } | 1734 | } |
@@ -1717,7 +1775,11 @@ module_exit(nvidiafb_exit); | |||
1717 | module_param(flatpanel, int, 0); | 1775 | module_param(flatpanel, int, 0); |
1718 | MODULE_PARM_DESC(flatpanel, | 1776 | MODULE_PARM_DESC(flatpanel, |
1719 | "Enables experimental flat panel support for some chipsets. " | 1777 | "Enables experimental flat panel support for some chipsets. " |
1720 | "(0 or 1=enabled) (default=0)"); | 1778 | "(0=disabled, 1=enabled, -1=autodetect) (default=-1)"); |
1779 | module_param(fpdither, int, 0); | ||
1780 | MODULE_PARM_DESC(fpdither, | ||
1781 | "Enables dithering of flat panel for 6 bits panels. " | ||
1782 | "(0=disabled, 1=enabled, -1=autodetect) (default=-1)"); | ||
1721 | module_param(hwcur, int, 0); | 1783 | module_param(hwcur, int, 0); |
1722 | MODULE_PARM_DESC(hwcur, | 1784 | MODULE_PARM_DESC(hwcur, |
1723 | "Enables hardware cursor implementation. (0 or 1=enabled) " | 1785 | "Enables hardware cursor implementation. (0 or 1=enabled) " |