aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/nvidia
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2005-11-07 04:00:30 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-07 10:53:49 -0500
commit85f1503aff46089acd9f780b5259752839cf0162 (patch)
tree2e517636de893ec886e05981171484f655234c63 /drivers/video/nvidia
parentecc41d5e0267de2c010e0fdf8da3c9e3e394f752 (diff)
[PATCH] nvidiafb: Fix mode setting & PPC support
This patch fixes nvifiafb mode setting code to be closer to what the X driver does, which actually makes it work on the 5200FX I have access to. It also fix the routine that gets the EDID from Open Firmware on PPC, it was broken in various ways and would crash at boot. Compared to the patch I posted to linux-fbdev last week, this one just changes a printk to be closer to the other ones in the driver. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: "Antonino A. Daplas" <adaplas@hotpop.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/video/nvidia')
-rw-r--r--drivers/video/nvidia/nv_of.c64
-rw-r--r--drivers/video/nvidia/nv_proto.h14
-rw-r--r--drivers/video/nvidia/nv_setup.c16
-rw-r--r--drivers/video/nvidia/nvidia.c84
4 files changed, 136 insertions, 42 deletions
diff --git a/drivers/video/nvidia/nv_of.c b/drivers/video/nvidia/nv_of.c
index 4fa2cf9a8af2..7a03d040b1a3 100644
--- a/drivers/video/nvidia/nv_of.c
+++ b/drivers/video/nvidia/nv_of.c
@@ -27,34 +27,60 @@
27#include "nv_local.h" 27#include "nv_local.h"
28#include "nv_proto.h" 28#include "nv_proto.h"
29 29
30void nvidia_create_i2c_busses(struct nvidia_par *par) {} 30#include "../edid.h"
31void nvidia_delete_i2c_busses(struct nvidia_par *par) {}
32 31
33int nvidia_probe_i2c_connector(struct fb_info *info, int conn, u8 **out_edid) 32int nvidia_probe_of_connector(struct fb_info *info, int conn, u8 **out_edid)
34{ 33{
35 struct nvidia_par *par = info->par; 34 struct nvidia_par *par = info->par;
36 struct device_node *dp; 35 struct device_node *parent, *dp;
37 unsigned char *pedid = NULL; 36 unsigned char *pedid = NULL;
38 unsigned char *disptype = NULL;
39 static char *propnames[] = { 37 static char *propnames[] = {
40 "DFP,EDID", "LCD,EDID", "EDID", "EDID1", "EDID,B", "EDID,A", NULL }; 38 "DFP,EDID", "LCD,EDID", "EDID", "EDID1",
39 "EDID,B", "EDID,A", NULL };
41 int i; 40 int i;
42 41
43 dp = pci_device_to_OF_node(par->pci_dev); 42 parent = pci_device_to_OF_node(par->pci_dev);
44 for (; dp != NULL; dp = dp->child) { 43 if (parent == NULL)
45 disptype = (unsigned char *)get_property(dp, "display-type", NULL); 44 return -1;
46 if (disptype == NULL) 45 if (par->twoHeads) {
47 continue; 46 char *pname;
48 if (strncmp(disptype, "LCD", 3) != 0) 47 int len;
49 continue; 48
49 for (dp = NULL;
50 (dp = of_get_next_child(parent, dp)) != NULL;) {
51 pname = (char *)get_property(dp, "name", NULL);
52 if (!pname)
53 continue;
54 len = strlen(pname);
55 if ((pname[len-1] == 'A' && conn == 1) ||
56 (pname[len-1] == 'B' && conn == 2)) {
57 for (i = 0; propnames[i] != NULL; ++i) {
58 pedid = (unsigned char *)
59 get_property(dp, propnames[i],
60 NULL);
61 if (pedid != NULL)
62 break;
63 }
64 of_node_put(dp);
65 break;
66 }
67 }
68 }
69 if (pedid == NULL) {
50 for (i = 0; propnames[i] != NULL; ++i) { 70 for (i = 0; propnames[i] != NULL; ++i) {
51 pedid = (unsigned char *) 71 pedid = (unsigned char *)
52 get_property(dp, propnames[i], NULL); 72 get_property(parent, propnames[i], NULL);
53 if (pedid != NULL) { 73 if (pedid != NULL)
54 *out_edid = pedid; 74 break;
55 return 0;
56 }
57 } 75 }
58 } 76 }
59 return 1; 77 if (pedid) {
78 *out_edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
79 if (*out_edid == NULL)
80 return -1;
81 memcpy(*out_edid, pedid, EDID_LENGTH);
82 printk(KERN_DEBUG "nvidiafb: Found OF EDID for head %d\n", conn);
83 return 0;
84 }
85 return -1;
60} 86}
diff --git a/drivers/video/nvidia/nv_proto.h b/drivers/video/nvidia/nv_proto.h
index cac44fc7f587..3d35b77a4af5 100644
--- a/drivers/video/nvidia/nv_proto.h
+++ b/drivers/video/nvidia/nv_proto.h
@@ -31,7 +31,7 @@ int NVShowHideCursor(struct nvidia_par *par, int);
31void NVLockUnlock(struct nvidia_par *par, int); 31void NVLockUnlock(struct nvidia_par *par, int);
32 32
33/* in nvidia-i2c.c */ 33/* in nvidia-i2c.c */
34#if defined(CONFIG_FB_NVIDIA_I2C) || defined (CONFIG_PPC_OF) 34#ifdef CONFIG_FB_NVIDIA_I2C
35void nvidia_create_i2c_busses(struct nvidia_par *par); 35void nvidia_create_i2c_busses(struct nvidia_par *par);
36void nvidia_delete_i2c_busses(struct nvidia_par *par); 36void nvidia_delete_i2c_busses(struct nvidia_par *par);
37int nvidia_probe_i2c_connector(struct fb_info *info, int conn, 37int nvidia_probe_i2c_connector(struct fb_info *info, int conn,
@@ -39,10 +39,14 @@ int nvidia_probe_i2c_connector(struct fb_info *info, int conn,
39#else 39#else
40#define nvidia_create_i2c_busses(...) 40#define nvidia_create_i2c_busses(...)
41#define nvidia_delete_i2c_busses(...) 41#define nvidia_delete_i2c_busses(...)
42#define nvidia_probe_i2c_connector(p, c, edid) \ 42#define nvidia_probe_i2c_connector(p, c, edid) (-1)
43do { \ 43#endif
44 *(edid) = NULL; \ 44
45} while(0) 45#ifdef CONFIG_FB_OF
46int nvidia_probe_of_connector(struct fb_info *info, int conn,
47 u8 ** out_edid);
48#else
49#define nvidia_probe_of_connector(p, c, edid) (-1)
46#endif 50#endif
47 51
48/* in nv_accel.c */ 52/* in nv_accel.c */
diff --git a/drivers/video/nvidia/nv_setup.c b/drivers/video/nvidia/nv_setup.c
index 11c84178f420..1f06a9f1bd0f 100644
--- a/drivers/video/nvidia/nv_setup.c
+++ b/drivers/video/nvidia/nv_setup.c
@@ -190,9 +190,9 @@ static int NVIsConnected(struct nvidia_par *par, int output)
190 present = (NV_RD32(PRAMDAC, 0x0608) & (1 << 28)) ? 1 : 0; 190 present = (NV_RD32(PRAMDAC, 0x0608) & (1 << 28)) ? 1 : 0;
191 191
192 if (present) 192 if (present)
193 printk("nvidiafb: CRTC%i found\n", output); 193 printk("nvidiafb: CRTC%i analog found\n", output);
194 else 194 else
195 printk("nvidiafb: CRTC%i not found\n", output); 195 printk("nvidiafb: CRTC%i analog not found\n", output);
196 196
197 NV_WR32(par->PRAMDAC0, 0x0608, NV_RD32(par->PRAMDAC0, 0x0608) & 197 NV_WR32(par->PRAMDAC0, 0x0608, NV_RD32(par->PRAMDAC0, 0x0608) &
198 0x0000EFFF); 198 0x0000EFFF);
@@ -305,6 +305,9 @@ void NVCommonSetup(struct fb_info *info)
305 int FlatPanel = -1; /* really means the CRTC is slaved */ 305 int FlatPanel = -1; /* really means the CRTC is slaved */
306 int Television = 0; 306 int Television = 0;
307 307
308 memset(&monitorA, 0, sizeof(struct fb_monspecs));
309 memset(&monitorB, 0, sizeof(struct fb_monspecs));
310
308 par->PRAMIN = par->REGS + (0x00710000 / 4); 311 par->PRAMIN = par->REGS + (0x00710000 / 4);
309 par->PCRTC0 = par->REGS + (0x00600000 / 4); 312 par->PCRTC0 = par->REGS + (0x00600000 / 4);
310 par->PRAMDAC0 = par->REGS + (0x00680000 / 4); 313 par->PRAMDAC0 = par->REGS + (0x00680000 / 4);
@@ -401,7 +404,8 @@ void NVCommonSetup(struct fb_info *info)
401 nvidia_create_i2c_busses(par); 404 nvidia_create_i2c_busses(par);
402 if (!par->twoHeads) { 405 if (!par->twoHeads) {
403 par->CRTCnumber = 0; 406 par->CRTCnumber = 0;
404 nvidia_probe_i2c_connector(info, 1, &edidA); 407 if (nvidia_probe_i2c_connector(info, 1, &edidA))
408 nvidia_probe_of_connector(info, 1, &edidA);
405 if (edidA && !fb_parse_edid(edidA, &var)) { 409 if (edidA && !fb_parse_edid(edidA, &var)) {
406 printk("nvidiafb: EDID found from BUS1\n"); 410 printk("nvidiafb: EDID found from BUS1\n");
407 monA = &monitorA; 411 monA = &monitorA;
@@ -488,14 +492,16 @@ void NVCommonSetup(struct fb_info *info)
488 oldhead = NV_RD32(par->PCRTC0, 0x00000860); 492 oldhead = NV_RD32(par->PCRTC0, 0x00000860);
489 NV_WR32(par->PCRTC0, 0x00000860, oldhead | 0x00000010); 493 NV_WR32(par->PCRTC0, 0x00000860, oldhead | 0x00000010);
490 494
491 nvidia_probe_i2c_connector(info, 1, &edidA); 495 if (nvidia_probe_i2c_connector(info, 1, &edidA))
496 nvidia_probe_of_connector(info, 1, &edidA);
492 if (edidA && !fb_parse_edid(edidA, &var)) { 497 if (edidA && !fb_parse_edid(edidA, &var)) {
493 printk("nvidiafb: EDID found from BUS1\n"); 498 printk("nvidiafb: EDID found from BUS1\n");
494 monA = &monitorA; 499 monA = &monitorA;
495 fb_edid_to_monspecs(edidA, monA); 500 fb_edid_to_monspecs(edidA, monA);
496 } 501 }
497 502
498 nvidia_probe_i2c_connector(info, 2, &edidB); 503 if (nvidia_probe_i2c_connector(info, 2, &edidB))
504 nvidia_probe_of_connector(info, 2, &edidB);
499 if (edidB && !fb_parse_edid(edidB, &var)) { 505 if (edidB && !fb_parse_edid(edidB, &var)) {
500 printk("nvidiafb: EDID found from BUS2\n"); 506 printk("nvidiafb: EDID found from BUS2\n");
501 monB = &monitorB; 507 monB = &monitorB;
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index 308defc389a2..96d51144094a 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -627,41 +627,85 @@ static void nvidia_save_vga(struct nvidia_par *par,
627 NVTRACE_LEAVE(); 627 NVTRACE_LEAVE();
628} 628}
629 629
630#undef DUMP_REG
631
630static void nvidia_write_regs(struct nvidia_par *par) 632static void nvidia_write_regs(struct nvidia_par *par)
631{ 633{
632 struct _riva_hw_state *state = &par->ModeReg; 634 struct _riva_hw_state *state = &par->ModeReg;
633 int i; 635 int i;
634 636
635 NVTRACE_ENTER(); 637 NVTRACE_ENTER();
636 NVWriteCrtc(par, 0x11, 0x00);
637
638 NVLockUnlock(par, 0);
639 638
640 NVLoadStateExt(par, state); 639 NVLoadStateExt(par, state);
641 640
642 NVWriteMiscOut(par, state->misc_output); 641 NVWriteMiscOut(par, state->misc_output);
643 642
643 for (i = 1; i < NUM_SEQ_REGS; i++) {
644#ifdef DUMP_REG
645 printk(" SEQ[%02x] = %08x\n", i, state->seq[i]);
646#endif
647 NVWriteSeq(par, i, state->seq[i]);
648 }
649
650 /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 of CRTC[17] */
651 NVWriteCrtc(par, 0x11, state->crtc[0x11] & ~0x80);
652
644 for (i = 0; i < NUM_CRT_REGS; i++) { 653 for (i = 0; i < NUM_CRT_REGS; i++) {
645 switch (i) { 654 switch (i) {
646 case 0x19: 655 case 0x19:
647 case 0x20 ... 0x40: 656 case 0x20 ... 0x40:
648 break; 657 break;
649 default: 658 default:
659#ifdef DUMP_REG
660 printk("CRTC[%02x] = %08x\n", i, state->crtc[i]);
661#endif
650 NVWriteCrtc(par, i, state->crtc[i]); 662 NVWriteCrtc(par, i, state->crtc[i]);
651 } 663 }
652 } 664 }
653 665
654 for (i = 0; i < NUM_ATC_REGS; i++) 666 for (i = 0; i < NUM_GRC_REGS; i++) {
655 NVWriteAttr(par, i, state->attr[i]); 667#ifdef DUMP_REG
656 668 printk(" GRA[%02x] = %08x\n", i, state->gra[i]);
657 for (i = 0; i < NUM_GRC_REGS; i++) 669#endif
658 NVWriteGr(par, i, state->gra[i]); 670 NVWriteGr(par, i, state->gra[i]);
671 }
672
673 for (i = 0; i < NUM_ATC_REGS; i++) {
674#ifdef DUMP_REG
675 printk("ATTR[%02x] = %08x\n", i, state->attr[i]);
676#endif
677 NVWriteAttr(par, i, state->attr[i]);
678 }
659 679
660 for (i = 0; i < NUM_SEQ_REGS; i++)
661 NVWriteSeq(par, i, state->seq[i]);
662 NVTRACE_LEAVE(); 680 NVTRACE_LEAVE();
663} 681}
664 682
683static void nvidia_vga_protect(struct nvidia_par *par, int on)
684{
685 unsigned char tmp;
686
687 if (on) {
688 /*
689 * Turn off screen and disable sequencer.
690 */
691 tmp = NVReadSeq(par, 0x01);
692
693 NVWriteSeq(par, 0x00, 0x01); /* Synchronous Reset */
694 NVWriteSeq(par, 0x01, tmp | 0x20); /* disable the display */
695 } else {
696 /*
697 * Reenable sequencer, then turn on screen.
698 */
699
700 tmp = NVReadSeq(par, 0x01);
701
702 NVWriteSeq(par, 0x01, tmp & ~0x20); /* reenable display */
703 NVWriteSeq(par, 0x00, 0x03); /* End Reset */
704 }
705}
706
707
708
665static int nvidia_calc_regs(struct fb_info *info) 709static int nvidia_calc_regs(struct fb_info *info)
666{ 710{
667 struct nvidia_par *par = info->par; 711 struct nvidia_par *par = info->par;
@@ -868,7 +912,7 @@ static void nvidia_init_vga(struct fb_info *info)
868 for (i = 0; i < 0x10; i++) 912 for (i = 0; i < 0x10; i++)
869 state->attr[i] = i; 913 state->attr[i] = i;
870 state->attr[0x10] = 0x41; 914 state->attr[0x10] = 0x41;
871 state->attr[0x11] = 0x01; 915 state->attr[0x11] = 0xff;
872 state->attr[0x12] = 0x0f; 916 state->attr[0x12] = 0x0f;
873 state->attr[0x13] = 0x00; 917 state->attr[0x13] = 0x00;
874 state->attr[0x14] = 0x00; 918 state->attr[0x14] = 0x00;
@@ -991,7 +1035,6 @@ static int nvidiafb_set_par(struct fb_info *info)
991 1035
992 nvidia_init_vga(info); 1036 nvidia_init_vga(info);
993 nvidia_calc_regs(info); 1037 nvidia_calc_regs(info);
994 nvidia_write_regs(par);
995 1038
996 NVLockUnlock(par, 0); 1039 NVLockUnlock(par, 0);
997 if (par->twoHeads) { 1040 if (par->twoHeads) {
@@ -1000,7 +1043,22 @@ static int nvidiafb_set_par(struct fb_info *info)
1000 NVLockUnlock(par, 0); 1043 NVLockUnlock(par, 0);
1001 } 1044 }
1002 1045
1003 NVWriteCrtc(par, 0x11, 0x00); 1046 nvidia_vga_protect(par, 1);
1047
1048 nvidia_write_regs(par);
1049
1050#if defined (__BIG_ENDIAN)
1051 /* turn on LFB swapping */
1052 {
1053 unsigned char tmp;
1054
1055 VGA_WR08(par->PCIO, 0x3d4, 0x46);
1056 tmp = VGA_RD08(par->PCIO, 0x3d5);
1057 tmp |= (1 << 7);
1058 VGA_WR08(par->PCIO, 0x3d5, tmp);
1059 }
1060#endif
1061
1004 info->fix.line_length = (info->var.xres_virtual * 1062 info->fix.line_length = (info->var.xres_virtual *
1005 info->var.bits_per_pixel) >> 3; 1063 info->var.bits_per_pixel) >> 3;
1006 if (info->var.accel_flags) { 1064 if (info->var.accel_flags) {
@@ -1022,7 +1080,7 @@ static int nvidiafb_set_par(struct fb_info *info)
1022 1080
1023 par->cursor_reset = 1; 1081 par->cursor_reset = 1;
1024 1082
1025 NVWriteCrtc(par, 0x11, 0xff); 1083 nvidia_vga_protect(par, 0);
1026 1084
1027 NVTRACE_LEAVE(); 1085 NVTRACE_LEAVE();
1028 return 0; 1086 return 0;