aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorDavid Ung <davidu@nvidia.com>2015-01-13 22:04:27 -0500
committerTomi Valkeinen <tomi.valkeinen@ti.com>2015-01-15 06:33:41 -0500
commit72bbf10bf0fdaa097252149ef3a9b74c48a0d683 (patch)
tree11abf3f7a0355b29782c1f1738122a90288a52db /drivers/video
parent8f5ee77bb8d162abe28ff8cd56f36e825d143207 (diff)
video: fbdev: Validate mode timing against monspec
fbmon may generate mode timings that are out of spec of the monitor. eg DELL U2410 has a max clock 170mhz but advertises a resolutions of 1920x1200@60 in its Standard Timings using 2byte code of D1 00. When this is looked up in the DMT table it gives it a 193mhz clock. Although the DELL monitor supports 1920x1200@60, it can only run with reduced timings at 154mhz or DMT id 0x44 which has no STD 2byte code. This patch checks to see if the mode can be supported by the monitor by comparing against monspecs.dclkmax. Signed-off-by: David Ung <davidu@nvidia.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/fbdev/core/fbmon.c27
1 files changed, 18 insertions, 9 deletions
diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c
index 0f234c15ece3..95338593ebf4 100644
--- a/drivers/video/fbdev/core/fbmon.c
+++ b/drivers/video/fbdev/core/fbmon.c
@@ -496,7 +496,7 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
496} 496}
497 497
498static int get_std_timing(unsigned char *block, struct fb_videomode *mode, 498static int get_std_timing(unsigned char *block, struct fb_videomode *mode,
499 int ver, int rev) 499 int ver, int rev, const struct fb_monspecs *specs)
500{ 500{
501 int i; 501 int i;
502 502
@@ -544,16 +544,23 @@ static int get_std_timing(unsigned char *block, struct fb_videomode *mode,
544 calc_mode_timings(xres, yres, refresh, mode); 544 calc_mode_timings(xres, yres, refresh, mode);
545 } 545 }
546 546
547 /* Check the mode we got is within valid spec of the monitor */
548 if (specs && specs->dclkmax
549 && PICOS2KHZ(mode->pixclock) * 1000 > specs->dclkmax) {
550 DPRINTK(" mode exceed max DCLK\n");
551 return 0;
552 }
553
547 return 1; 554 return 1;
548} 555}
549 556
550static int get_dst_timing(unsigned char *block, 557static int get_dst_timing(unsigned char *block, struct fb_videomode *mode,
551 struct fb_videomode *mode, int ver, int rev) 558 int ver, int rev, const struct fb_monspecs *specs)
552{ 559{
553 int j, num = 0; 560 int j, num = 0;
554 561
555 for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE) 562 for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE)
556 num += get_std_timing(block, &mode[num], ver, rev); 563 num += get_std_timing(block, &mode[num], ver, rev, specs);
557 564
558 return num; 565 return num;
559} 566}
@@ -609,7 +616,8 @@ static void get_detailed_timing(unsigned char *block,
609 * This function builds a mode database using the contents of the EDID 616 * This function builds a mode database using the contents of the EDID
610 * data 617 * data
611 */ 618 */
612static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize) 619static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize,
620 const struct fb_monspecs *specs)
613{ 621{
614 struct fb_videomode *mode, *m; 622 struct fb_videomode *mode, *m;
615 unsigned char *block; 623 unsigned char *block;
@@ -651,12 +659,13 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
651 DPRINTK(" Standard Timings\n"); 659 DPRINTK(" Standard Timings\n");
652 block = edid + STD_TIMING_DESCRIPTIONS_START; 660 block = edid + STD_TIMING_DESCRIPTIONS_START;
653 for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE) 661 for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE)
654 num += get_std_timing(block, &mode[num], ver, rev); 662 num += get_std_timing(block, &mode[num], ver, rev, specs);
655 663
656 block = edid + DETAILED_TIMING_DESCRIPTIONS_START; 664 block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
657 for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { 665 for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
658 if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa) 666 if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa)
659 num += get_dst_timing(block + 5, &mode[num], ver, rev); 667 num += get_dst_timing(block + 5, &mode[num],
668 ver, rev, specs);
660 } 669 }
661 670
662 /* Yikes, EDID data is totally useless */ 671 /* Yikes, EDID data is totally useless */
@@ -715,7 +724,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
715 int num_modes, hz, hscan, pixclock; 724 int num_modes, hz, hscan, pixclock;
716 int vtotal, htotal; 725 int vtotal, htotal;
717 726
718 modes = fb_create_modedb(edid, &num_modes); 727 modes = fb_create_modedb(edid, &num_modes, specs);
719 if (!modes) { 728 if (!modes) {
720 DPRINTK("None Available\n"); 729 DPRINTK("None Available\n");
721 return 1; 730 return 1;
@@ -972,7 +981,7 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
972 DPRINTK(" Display Characteristics:\n"); 981 DPRINTK(" Display Characteristics:\n");
973 get_monspecs(edid, specs); 982 get_monspecs(edid, specs);
974 983
975 specs->modedb = fb_create_modedb(edid, &specs->modedb_len); 984 specs->modedb = fb_create_modedb(edid, &specs->modedb_len, specs);
976 985
977 /* 986 /*
978 * Workaround for buggy EDIDs that sets that the first 987 * Workaround for buggy EDIDs that sets that the first