diff options
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 46 |
1 files changed, 36 insertions, 10 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 90d76bacff17..3c0d2b3aed76 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -109,7 +109,9 @@ static struct edid_quirk { | |||
109 | 109 | ||
110 | 110 | ||
111 | /* Valid EDID header has these bytes */ | 111 | /* Valid EDID header has these bytes */ |
112 | static u8 edid_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; | 112 | static const u8 edid_header[] = { |
113 | 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 | ||
114 | }; | ||
113 | 115 | ||
114 | /** | 116 | /** |
115 | * edid_is_valid - sanity check EDID data | 117 | * edid_is_valid - sanity check EDID data |
@@ -500,6 +502,19 @@ static struct drm_display_mode *drm_find_dmt(struct drm_device *dev, | |||
500 | } | 502 | } |
501 | return mode; | 503 | return mode; |
502 | } | 504 | } |
505 | |||
506 | /* | ||
507 | * 0 is reserved. The spec says 0x01 fill for unused timings. Some old | ||
508 | * monitors fill with ascii space (0x20) instead. | ||
509 | */ | ||
510 | static int | ||
511 | bad_std_timing(u8 a, u8 b) | ||
512 | { | ||
513 | return (a == 0x00 && b == 0x00) || | ||
514 | (a == 0x01 && b == 0x01) || | ||
515 | (a == 0x20 && b == 0x20); | ||
516 | } | ||
517 | |||
503 | /** | 518 | /** |
504 | * drm_mode_std - convert standard mode info (width, height, refresh) into mode | 519 | * drm_mode_std - convert standard mode info (width, height, refresh) into mode |
505 | * @t: standard timing params | 520 | * @t: standard timing params |
@@ -513,6 +528,7 @@ static struct drm_display_mode *drm_find_dmt(struct drm_device *dev, | |||
513 | */ | 528 | */ |
514 | struct drm_display_mode *drm_mode_std(struct drm_device *dev, | 529 | struct drm_display_mode *drm_mode_std(struct drm_device *dev, |
515 | struct std_timing *t, | 530 | struct std_timing *t, |
531 | int revision, | ||
516 | int timing_level) | 532 | int timing_level) |
517 | { | 533 | { |
518 | struct drm_display_mode *mode; | 534 | struct drm_display_mode *mode; |
@@ -523,14 +539,20 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev, | |||
523 | unsigned vfreq = (t->vfreq_aspect & EDID_TIMING_VFREQ_MASK) | 539 | unsigned vfreq = (t->vfreq_aspect & EDID_TIMING_VFREQ_MASK) |
524 | >> EDID_TIMING_VFREQ_SHIFT; | 540 | >> EDID_TIMING_VFREQ_SHIFT; |
525 | 541 | ||
542 | if (bad_std_timing(t->hsize, t->vfreq_aspect)) | ||
543 | return NULL; | ||
544 | |||
526 | /* According to the EDID spec, the hdisplay = hsize * 8 + 248 */ | 545 | /* According to the EDID spec, the hdisplay = hsize * 8 + 248 */ |
527 | hsize = t->hsize * 8 + 248; | 546 | hsize = t->hsize * 8 + 248; |
528 | /* vrefresh_rate = vfreq + 60 */ | 547 | /* vrefresh_rate = vfreq + 60 */ |
529 | vrefresh_rate = vfreq + 60; | 548 | vrefresh_rate = vfreq + 60; |
530 | /* the vdisplay is calculated based on the aspect ratio */ | 549 | /* the vdisplay is calculated based on the aspect ratio */ |
531 | if (aspect_ratio == 0) | 550 | if (aspect_ratio == 0) { |
532 | vsize = (hsize * 10) / 16; | 551 | if (revision < 3) |
533 | else if (aspect_ratio == 1) | 552 | vsize = hsize; |
553 | else | ||
554 | vsize = (hsize * 10) / 16; | ||
555 | } else if (aspect_ratio == 1) | ||
534 | vsize = (hsize * 3) / 4; | 556 | vsize = (hsize * 3) / 4; |
535 | else if (aspect_ratio == 2) | 557 | else if (aspect_ratio == 2) |
536 | vsize = (hsize * 4) / 5; | 558 | vsize = (hsize * 4) / 5; |
@@ -538,7 +560,8 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev, | |||
538 | vsize = (hsize * 9) / 16; | 560 | vsize = (hsize * 9) / 16; |
539 | /* HDTV hack */ | 561 | /* HDTV hack */ |
540 | if (hsize == 1360 && vsize == 765 && vrefresh_rate == 60) { | 562 | if (hsize == 1360 && vsize == 765 && vrefresh_rate == 60) { |
541 | mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); | 563 | mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0, |
564 | false); | ||
542 | mode->hdisplay = 1366; | 565 | mode->hdisplay = 1366; |
543 | mode->vsync_start = mode->vsync_start - 1; | 566 | mode->vsync_start = mode->vsync_start - 1; |
544 | mode->vsync_end = mode->vsync_end - 1; | 567 | mode->vsync_end = mode->vsync_end - 1; |
@@ -557,7 +580,8 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev, | |||
557 | mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); | 580 | mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); |
558 | break; | 581 | break; |
559 | case LEVEL_CVT: | 582 | case LEVEL_CVT: |
560 | mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); | 583 | mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0, |
584 | false); | ||
561 | break; | 585 | break; |
562 | } | 586 | } |
563 | return mode; | 587 | return mode; |
@@ -779,7 +803,7 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid | |||
779 | continue; | 803 | continue; |
780 | 804 | ||
781 | newmode = drm_mode_std(dev, &edid->standard_timings[i], | 805 | newmode = drm_mode_std(dev, &edid->standard_timings[i], |
782 | timing_level); | 806 | edid->revision, timing_level); |
783 | if (newmode) { | 807 | if (newmode) { |
784 | drm_mode_probed_add(connector, newmode); | 808 | drm_mode_probed_add(connector, newmode); |
785 | modes++; | 809 | modes++; |
@@ -829,13 +853,13 @@ static int add_detailed_info(struct drm_connector *connector, | |||
829 | case EDID_DETAIL_MONITOR_CPDATA: | 853 | case EDID_DETAIL_MONITOR_CPDATA: |
830 | break; | 854 | break; |
831 | case EDID_DETAIL_STD_MODES: | 855 | case EDID_DETAIL_STD_MODES: |
832 | /* Five modes per detailed section */ | 856 | for (j = 0; j < 6; i++) { |
833 | for (j = 0; j < 5; i++) { | ||
834 | struct std_timing *std; | 857 | struct std_timing *std; |
835 | struct drm_display_mode *newmode; | 858 | struct drm_display_mode *newmode; |
836 | 859 | ||
837 | std = &data->data.timings[j]; | 860 | std = &data->data.timings[j]; |
838 | newmode = drm_mode_std(dev, std, | 861 | newmode = drm_mode_std(dev, std, |
862 | edid->revision, | ||
839 | timing_level); | 863 | timing_level); |
840 | if (newmode) { | 864 | if (newmode) { |
841 | drm_mode_probed_add(connector, newmode); | 865 | drm_mode_probed_add(connector, newmode); |
@@ -964,7 +988,9 @@ static int add_detailed_info_eedid(struct drm_connector *connector, | |||
964 | struct drm_display_mode *newmode; | 988 | struct drm_display_mode *newmode; |
965 | 989 | ||
966 | std = &data->data.timings[j]; | 990 | std = &data->data.timings[j]; |
967 | newmode = drm_mode_std(dev, std, timing_level); | 991 | newmode = drm_mode_std(dev, std, |
992 | edid->revision, | ||
993 | timing_level); | ||
968 | if (newmode) { | 994 | if (newmode) { |
969 | drm_mode_probed_add(connector, newmode); | 995 | drm_mode_probed_add(connector, newmode); |
970 | modes++; | 996 | modes++; |