Commit 85f1503aff46089acd9f780b5259752839cf0162

Authored by Benjamin Herrenschmidt
Committed by Linus Torvalds
1 parent ecc41d5e02

[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>

Showing 5 changed files with 137 additions and 43 deletions Side-by-side Diff

drivers/video/Kconfig
... ... @@ -703,7 +703,7 @@
703 703  
704 704 config FB_NVIDIA_I2C
705 705 bool "Enable DDC Support"
706   - depends on FB_NVIDIA && !PPC_OF
  706 + depends on FB_NVIDIA
707 707 help
708 708 This enables I2C support for nVidia Chipsets. This is used
709 709 only for getting EDID information from the attached display
drivers/video/nvidia/nv_of.c
... ... @@ -27,35 +27,61 @@
27 27 #include "nv_local.h"
28 28 #include "nv_proto.h"
29 29  
30   -void nvidia_create_i2c_busses(struct nvidia_par *par) {}
31   -void nvidia_delete_i2c_busses(struct nvidia_par *par) {}
  30 +#include "../edid.h"
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 34 struct nvidia_par *par = info->par;
36   - struct device_node *dp;
  35 + struct device_node *parent, *dp;
37 36 unsigned char *pedid = NULL;
38   - unsigned char *disptype = NULL;
39 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 40 int i;
42 41  
43   - dp = pci_device_to_OF_node(par->pci_dev);
44   - for (; dp != NULL; dp = dp->child) {
45   - disptype = (unsigned char *)get_property(dp, "display-type", NULL);
46   - if (disptype == NULL)
47   - continue;
48   - if (strncmp(disptype, "LCD", 3) != 0)
49   - continue;
  42 + parent = pci_device_to_OF_node(par->pci_dev);
  43 + if (parent == NULL)
  44 + return -1;
  45 + if (par->twoHeads) {
  46 + char *pname;
  47 + int len;
  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 70 for (i = 0; propnames[i] != NULL; ++i) {
51 71 pedid = (unsigned char *)
52   - get_property(dp, propnames[i], NULL);
53   - if (pedid != NULL) {
54   - *out_edid = pedid;
55   - return 0;
56   - }
  72 + get_property(parent, propnames[i], NULL);
  73 + if (pedid != NULL)
  74 + break;
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 }
drivers/video/nvidia/nv_proto.h
... ... @@ -31,7 +31,7 @@
31 31 void NVLockUnlock(struct nvidia_par *par, int);
32 32  
33 33 /* in nvidia-i2c.c */
34   -#if defined(CONFIG_FB_NVIDIA_I2C) || defined (CONFIG_PPC_OF)
  34 +#ifdef CONFIG_FB_NVIDIA_I2C
35 35 void nvidia_create_i2c_busses(struct nvidia_par *par);
36 36 void nvidia_delete_i2c_busses(struct nvidia_par *par);
37 37 int nvidia_probe_i2c_connector(struct fb_info *info, int conn,
... ... @@ -39,10 +39,14 @@
39 39 #else
40 40 #define nvidia_create_i2c_busses(...)
41 41 #define nvidia_delete_i2c_busses(...)
42   -#define nvidia_probe_i2c_connector(p, c, edid) \
43   -do { \
44   - *(edid) = NULL; \
45   -} while(0)
  42 +#define nvidia_probe_i2c_connector(p, c, edid) (-1)
  43 +#endif
  44 +
  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 50 #endif
47 51  
48 52 /* in nv_accel.c */
drivers/video/nvidia/nv_setup.c
... ... @@ -190,9 +190,9 @@
190 190 present = (NV_RD32(PRAMDAC, 0x0608) & (1 << 28)) ? 1 : 0;
191 191  
192 192 if (present)
193   - printk("nvidiafb: CRTC%i found\n", output);
  193 + printk("nvidiafb: CRTC%i analog found\n", output);
194 194 else
195   - printk("nvidiafb: CRTC%i not found\n", output);
  195 + printk("nvidiafb: CRTC%i analog not found\n", output);
196 196  
197 197 NV_WR32(par->PRAMDAC0, 0x0608, NV_RD32(par->PRAMDAC0, 0x0608) &
198 198 0x0000EFFF);
... ... @@ -305,6 +305,9 @@
305 305 int FlatPanel = -1; /* really means the CRTC is slaved */
306 306 int Television = 0;
307 307  
  308 + memset(&monitorA, 0, sizeof(struct fb_monspecs));
  309 + memset(&monitorB, 0, sizeof(struct fb_monspecs));
  310 +
308 311 par->PRAMIN = par->REGS + (0x00710000 / 4);
309 312 par->PCRTC0 = par->REGS + (0x00600000 / 4);
310 313 par->PRAMDAC0 = par->REGS + (0x00680000 / 4);
... ... @@ -401,7 +404,8 @@
401 404 nvidia_create_i2c_busses(par);
402 405 if (!par->twoHeads) {
403 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 409 if (edidA && !fb_parse_edid(edidA, &var)) {
406 410 printk("nvidiafb: EDID found from BUS1\n");
407 411 monA = &monitorA;
408 412  
... ... @@ -488,14 +492,16 @@
488 492 oldhead = NV_RD32(par->PCRTC0, 0x00000860);
489 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 497 if (edidA && !fb_parse_edid(edidA, &var)) {
493 498 printk("nvidiafb: EDID found from BUS1\n");
494 499 monA = &monitorA;
495 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 505 if (edidB && !fb_parse_edid(edidB, &var)) {
500 506 printk("nvidiafb: EDID found from BUS2\n");
501 507 monB = &monitorB;
drivers/video/nvidia/nvidia.c
... ... @@ -627,41 +627,85 @@
627 627 NVTRACE_LEAVE();
628 628 }
629 629  
  630 +#undef DUMP_REG
  631 +
630 632 static void nvidia_write_regs(struct nvidia_par *par)
631 633 {
632 634 struct _riva_hw_state *state = &par->ModeReg;
633 635 int i;
634 636  
635 637 NVTRACE_ENTER();
636   - NVWriteCrtc(par, 0x11, 0x00);
637 638  
638   - NVLockUnlock(par, 0);
639   -
640 639 NVLoadStateExt(par, state);
641 640  
642 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 653 for (i = 0; i < NUM_CRT_REGS; i++) {
645 654 switch (i) {
646 655 case 0x19:
647 656 case 0x20 ... 0x40:
648 657 break;
649 658 default:
  659 +#ifdef DUMP_REG
  660 + printk("CRTC[%02x] = %08x\n", i, state->crtc[i]);
  661 +#endif
650 662 NVWriteCrtc(par, i, state->crtc[i]);
651 663 }
652 664 }
653 665  
654   - for (i = 0; i < NUM_ATC_REGS; i++)
655   - NVWriteAttr(par, i, state->attr[i]);
656   -
657   - for (i = 0; i < NUM_GRC_REGS; i++)
  666 + for (i = 0; i < NUM_GRC_REGS; i++) {
  667 +#ifdef DUMP_REG
  668 + printk(" GRA[%02x] = %08x\n", i, state->gra[i]);
  669 +#endif
658 670 NVWriteGr(par, i, state->gra[i]);
  671 + }
659 672  
660   - for (i = 0; i < NUM_SEQ_REGS; i++)
661   - NVWriteSeq(par, i, state->seq[i]);
  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 + }
  679 +
662 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 709 static int nvidia_calc_regs(struct fb_info *info)
666 710 {
667 711 struct nvidia_par *par = info->par;
... ... @@ -868,7 +912,7 @@
868 912 for (i = 0; i < 0x10; i++)
869 913 state->attr[i] = i;
870 914 state->attr[0x10] = 0x41;
871   - state->attr[0x11] = 0x01;
  915 + state->attr[0x11] = 0xff;
872 916 state->attr[0x12] = 0x0f;
873 917 state->attr[0x13] = 0x00;
874 918 state->attr[0x14] = 0x00;
... ... @@ -991,7 +1035,6 @@
991 1035  
992 1036 nvidia_init_vga(info);
993 1037 nvidia_calc_regs(info);
994   - nvidia_write_regs(par);
995 1038  
996 1039 NVLockUnlock(par, 0);
997 1040 if (par->twoHeads) {
... ... @@ -1000,7 +1043,22 @@
1000 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 1062 info->fix.line_length = (info->var.xres_virtual *
1005 1063 info->var.bits_per_pixel) >> 3;
1006 1064 if (info->var.accel_flags) {
... ... @@ -1022,7 +1080,7 @@
1022 1080  
1023 1081 par->cursor_reset = 1;
1024 1082  
1025   - NVWriteCrtc(par, 0x11, 0xff);
  1083 + nvidia_vga_protect(par, 0);
1026 1084  
1027 1085 NVTRACE_LEAVE();
1028 1086 return 0;