Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

authored by

Benjamin Herrenschmidt and committed by
Linus Torvalds
85f1503a ecc41d5e

+138 -44
+1 -1
drivers/video/Kconfig
··· 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
+46 -20
drivers/video/nvidia/nv_of.c
··· 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; 50 - for (i = 0; propnames[i] != NULL; ++i) { 51 - pedid = (unsigned char *) 52 - get_property(dp, propnames[i], NULL); 53 - if (pedid != NULL) { 54 - *out_edid = pedid; 55 - return 0; 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; 56 66 } 57 67 } 58 68 } 59 - return 1; 69 + if (pedid == NULL) { 70 + for (i = 0; propnames[i] != NULL; ++i) { 71 + pedid = (unsigned char *) 72 + get_property(parent, propnames[i], NULL); 73 + if (pedid != NULL) 74 + break; 75 + } 76 + } 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 }
+9 -5
drivers/video/nvidia/nv_proto.h
··· 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 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 */
+11 -5
drivers/video/nvidia/nv_setup.c
··· 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 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); ··· 404 401 nvidia_create_i2c_busses(par); 405 402 if (!par->twoHeads) { 406 403 par->CRTCnumber = 0; 407 - nvidia_probe_i2c_connector(info, 1, &edidA); 404 + if (nvidia_probe_i2c_connector(info, 1, &edidA)) 405 + nvidia_probe_of_connector(info, 1, &edidA); 408 406 if (edidA && !fb_parse_edid(edidA, &var)) { 409 407 printk("nvidiafb: EDID found from BUS1\n"); 410 408 monA = &monitorA; ··· 492 488 oldhead = NV_RD32(par->PCRTC0, 0x00000860); 493 489 NV_WR32(par->PCRTC0, 0x00000860, oldhead | 0x00000010); 494 490 495 - nvidia_probe_i2c_connector(info, 1, &edidA); 491 + if (nvidia_probe_i2c_connector(info, 1, &edidA)) 492 + nvidia_probe_of_connector(info, 1, &edidA); 496 493 if (edidA && !fb_parse_edid(edidA, &var)) { 497 494 printk("nvidiafb: EDID found from BUS1\n"); 498 495 monA = &monitorA; 499 496 fb_edid_to_monspecs(edidA, monA); 500 497 } 501 498 502 - nvidia_probe_i2c_connector(info, 2, &edidB); 499 + if (nvidia_probe_i2c_connector(info, 2, &edidB)) 500 + nvidia_probe_of_connector(info, 2, &edidB); 503 501 if (edidB && !fb_parse_edid(edidB, &var)) { 504 502 printk("nvidiafb: EDID found from BUS2\n"); 505 503 monB = &monitorB;
+71 -13
drivers/video/nvidia/nvidia.c
··· 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 - NVLockUnlock(par, 0); 639 638 640 639 NVLoadStateExt(par, state); 641 640 642 641 NVWriteMiscOut(par, state->misc_output); 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); 643 652 644 653 for (i = 0; i < NUM_CRT_REGS; i++) { 645 654 switch (i) { ··· 656 647 case 0x20 ... 0x40: 657 648 break; 658 649 default: 650 + #ifdef DUMP_REG 651 + printk("CRTC[%02x] = %08x\n", i, state->crtc[i]); 652 + #endif 659 653 NVWriteCrtc(par, i, state->crtc[i]); 660 654 } 661 655 } 662 656 663 - for (i = 0; i < NUM_ATC_REGS; i++) 664 - NVWriteAttr(par, i, state->attr[i]); 665 - 666 - for (i = 0; i < NUM_GRC_REGS; i++) 657 + for (i = 0; i < NUM_GRC_REGS; i++) { 658 + #ifdef DUMP_REG 659 + printk(" GRA[%02x] = %08x\n", i, state->gra[i]); 660 + #endif 667 661 NVWriteGr(par, i, state->gra[i]); 662 + } 668 663 669 - for (i = 0; i < NUM_SEQ_REGS; i++) 670 - NVWriteSeq(par, i, state->seq[i]); 664 + for (i = 0; i < NUM_ATC_REGS; i++) { 665 + #ifdef DUMP_REG 666 + printk("ATTR[%02x] = %08x\n", i, state->attr[i]); 667 + #endif 668 + NVWriteAttr(par, i, state->attr[i]); 669 + } 670 + 671 671 NVTRACE_LEAVE(); 672 672 } 673 + 674 + static void nvidia_vga_protect(struct nvidia_par *par, int on) 675 + { 676 + unsigned char tmp; 677 + 678 + if (on) { 679 + /* 680 + * Turn off screen and disable sequencer. 681 + */ 682 + tmp = NVReadSeq(par, 0x01); 683 + 684 + NVWriteSeq(par, 0x00, 0x01); /* Synchronous Reset */ 685 + NVWriteSeq(par, 0x01, tmp | 0x20); /* disable the display */ 686 + } else { 687 + /* 688 + * Reenable sequencer, then turn on screen. 689 + */ 690 + 691 + tmp = NVReadSeq(par, 0x01); 692 + 693 + NVWriteSeq(par, 0x01, tmp & ~0x20); /* reenable display */ 694 + NVWriteSeq(par, 0x00, 0x03); /* End Reset */ 695 + } 696 + } 697 + 698 + 673 699 674 700 static int nvidia_calc_regs(struct fb_info *info) 675 701 { ··· 912 868 for (i = 0; i < 0x10; i++) 913 869 state->attr[i] = i; 914 870 state->attr[0x10] = 0x41; 915 - state->attr[0x11] = 0x01; 871 + state->attr[0x11] = 0xff; 916 872 state->attr[0x12] = 0x0f; 917 873 state->attr[0x13] = 0x00; 918 874 state->attr[0x14] = 0x00; ··· 1035 991 1036 992 nvidia_init_vga(info); 1037 993 nvidia_calc_regs(info); 1038 - nvidia_write_regs(par); 1039 994 1040 995 NVLockUnlock(par, 0); 1041 996 if (par->twoHeads) { ··· 1043 1000 NVLockUnlock(par, 0); 1044 1001 } 1045 1002 1046 - NVWriteCrtc(par, 0x11, 0x00); 1003 + nvidia_vga_protect(par, 1); 1004 + 1005 + nvidia_write_regs(par); 1006 + 1007 + #if defined (__BIG_ENDIAN) 1008 + /* turn on LFB swapping */ 1009 + { 1010 + unsigned char tmp; 1011 + 1012 + VGA_WR08(par->PCIO, 0x3d4, 0x46); 1013 + tmp = VGA_RD08(par->PCIO, 0x3d5); 1014 + tmp |= (1 << 7); 1015 + VGA_WR08(par->PCIO, 0x3d5, tmp); 1016 + } 1017 + #endif 1018 + 1047 1019 info->fix.line_length = (info->var.xres_virtual * 1048 1020 info->var.bits_per_pixel) >> 3; 1049 1021 if (info->var.accel_flags) { ··· 1080 1022 1081 1023 par->cursor_reset = 1; 1082 1024 1083 - NVWriteCrtc(par, 0x11, 0xff); 1025 + nvidia_vga_protect(par, 0); 1084 1026 1085 1027 NVTRACE_LEAVE(); 1086 1028 return 0;