diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2005-11-07 04:00:30 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-07 10:53:49 -0500 |
commit | 85f1503aff46089acd9f780b5259752839cf0162 (patch) | |
tree | 2e517636de893ec886e05981171484f655234c63 /drivers/video/nvidia | |
parent | ecc41d5e0267de2c010e0fdf8da3c9e3e394f752 (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.c | 64 | ||||
-rw-r--r-- | drivers/video/nvidia/nv_proto.h | 14 | ||||
-rw-r--r-- | drivers/video/nvidia/nv_setup.c | 16 | ||||
-rw-r--r-- | drivers/video/nvidia/nvidia.c | 84 |
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 | ||
30 | void nvidia_create_i2c_busses(struct nvidia_par *par) {} | 30 | #include "../edid.h" |
31 | void nvidia_delete_i2c_busses(struct nvidia_par *par) {} | ||
32 | 31 | ||
33 | int nvidia_probe_i2c_connector(struct fb_info *info, int conn, u8 **out_edid) | 32 | int 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); | |||
31 | void NVLockUnlock(struct nvidia_par *par, int); | 31 | void 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 |
35 | void nvidia_create_i2c_busses(struct nvidia_par *par); | 35 | void nvidia_create_i2c_busses(struct nvidia_par *par); |
36 | void nvidia_delete_i2c_busses(struct nvidia_par *par); | 36 | void nvidia_delete_i2c_busses(struct nvidia_par *par); |
37 | int nvidia_probe_i2c_connector(struct fb_info *info, int conn, | 37 | int 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) |
43 | do { \ | 43 | #endif |
44 | *(edid) = NULL; \ | 44 | |
45 | } while(0) | 45 | #ifdef CONFIG_FB_OF |
46 | int 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 | |||
630 | static void nvidia_write_regs(struct nvidia_par *par) | 632 | static 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 | ||
683 | static 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 | |||
665 | static int nvidia_calc_regs(struct fb_info *info) | 709 | static 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; |