diff options
author | Adam Jackson <ajax@redhat.com> | 2009-12-03 17:44:38 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2009-12-03 17:53:32 -0500 |
commit | 07a5e6324abacad56a8e7bcb44dd404e84f75f57 (patch) | |
tree | 7284321ed859e29ecacb4ce1a8a6a58a4abb1942 /drivers/gpu/drm/drm_edid.c | |
parent | 7ac96a9cb4982140e206bf3b58236efb2498ab3f (diff) |
drm/edid: Add DMT modes to the pool if the monitor is GTF-capable
See also: http://bugzilla.redhat.com/539785
Signed-off-by: Adam Jackson <ajax@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 69 |
1 files changed, 65 insertions, 4 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 999571ab0b69..cc8e69682714 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -491,16 +491,17 @@ static struct drm_display_mode drm_dmt_modes[] = { | |||
491 | 3048, 3536, 0, 1600, 1603, 1609, 1682, 0, | 491 | 3048, 3536, 0, 1600, 1603, 1609, 1682, 0, |
492 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, | 492 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
493 | }; | 493 | }; |
494 | static const int drm_num_dmt_modes = | ||
495 | sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode); | ||
494 | 496 | ||
495 | static struct drm_display_mode *drm_find_dmt(struct drm_device *dev, | 497 | static struct drm_display_mode *drm_find_dmt(struct drm_device *dev, |
496 | int hsize, int vsize, int fresh) | 498 | int hsize, int vsize, int fresh) |
497 | { | 499 | { |
498 | int i, count; | 500 | int i; |
499 | struct drm_display_mode *ptr, *mode; | 501 | struct drm_display_mode *ptr, *mode; |
500 | 502 | ||
501 | count = sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode); | ||
502 | mode = NULL; | 503 | mode = NULL; |
503 | for (i = 0; i < count; i++) { | 504 | for (i = 0; i < drm_num_dmt_modes; i++) { |
504 | ptr = &drm_dmt_modes[i]; | 505 | ptr = &drm_dmt_modes[i]; |
505 | if (hsize == ptr->hdisplay && | 506 | if (hsize == ptr->hdisplay && |
506 | vsize == ptr->vdisplay && | 507 | vsize == ptr->vdisplay && |
@@ -838,6 +839,64 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid | |||
838 | return modes; | 839 | return modes; |
839 | } | 840 | } |
840 | 841 | ||
842 | /* | ||
843 | * XXX fix this for: | ||
844 | * - GTF secondary curve formula | ||
845 | * - EDID 1.4 range offsets | ||
846 | * - CVT extended bits | ||
847 | */ | ||
848 | static bool | ||
849 | mode_in_range(struct drm_display_mode *mode, struct detailed_timing *timing) | ||
850 | { | ||
851 | struct detailed_data_monitor_range *range; | ||
852 | int hsync, vrefresh; | ||
853 | |||
854 | range = &timing->data.other_data.data.range; | ||
855 | |||
856 | hsync = drm_mode_hsync(mode); | ||
857 | vrefresh = drm_mode_vrefresh(mode); | ||
858 | |||
859 | if (hsync < range->min_hfreq_khz || hsync > range->max_hfreq_khz) | ||
860 | return false; | ||
861 | |||
862 | if (vrefresh < range->min_vfreq || vrefresh > range->max_vfreq) | ||
863 | return false; | ||
864 | |||
865 | if (range->pixel_clock_mhz && range->pixel_clock_mhz != 0xff) { | ||
866 | /* be forgiving since it's in units of 10MHz */ | ||
867 | int max_clock = range->pixel_clock_mhz * 10 + 9; | ||
868 | max_clock *= 1000; | ||
869 | if (mode->clock > max_clock) | ||
870 | return false; | ||
871 | } | ||
872 | |||
873 | return true; | ||
874 | } | ||
875 | |||
876 | /* | ||
877 | * XXX If drm_dmt_modes ever regrows the CVT-R modes (and it will) this will | ||
878 | * need to account for them. | ||
879 | */ | ||
880 | static int drm_gtf_modes_for_range(struct drm_connector *connector, | ||
881 | struct detailed_timing *timing) | ||
882 | { | ||
883 | int i, modes = 0; | ||
884 | struct drm_display_mode *newmode; | ||
885 | struct drm_device *dev = connector->dev; | ||
886 | |||
887 | for (i = 0; i < drm_num_dmt_modes; i++) { | ||
888 | if (mode_in_range(drm_dmt_modes + i, timing)) { | ||
889 | newmode = drm_mode_duplicate(dev, &drm_dmt_modes[i]); | ||
890 | if (newmode) { | ||
891 | drm_mode_probed_add(connector, newmode); | ||
892 | modes++; | ||
893 | } | ||
894 | } | ||
895 | } | ||
896 | |||
897 | return modes; | ||
898 | } | ||
899 | |||
841 | static int add_detailed_modes(struct drm_connector *connector, | 900 | static int add_detailed_modes(struct drm_connector *connector, |
842 | struct detailed_timing *timing, | 901 | struct detailed_timing *timing, |
843 | struct edid *edid, u32 quirks, int preferred) | 902 | struct edid *edid, u32 quirks, int preferred) |
@@ -845,6 +904,7 @@ static int add_detailed_modes(struct drm_connector *connector, | |||
845 | int i, modes = 0; | 904 | int i, modes = 0; |
846 | struct detailed_non_pixel *data = &timing->data.other_data; | 905 | struct detailed_non_pixel *data = &timing->data.other_data; |
847 | int timing_level = standard_timing_level(edid); | 906 | int timing_level = standard_timing_level(edid); |
907 | int gtf = (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF); | ||
848 | struct drm_display_mode *newmode; | 908 | struct drm_display_mode *newmode; |
849 | struct drm_device *dev = connector->dev; | 909 | struct drm_device *dev = connector->dev; |
850 | 910 | ||
@@ -863,7 +923,8 @@ static int add_detailed_modes(struct drm_connector *connector, | |||
863 | /* other timing types */ | 923 | /* other timing types */ |
864 | switch (data->type) { | 924 | switch (data->type) { |
865 | case EDID_DETAIL_MONITOR_RANGE: | 925 | case EDID_DETAIL_MONITOR_RANGE: |
866 | /* Get monitor range data */ | 926 | if (gtf) |
927 | modes += drm_gtf_modes_for_range(connector, timing); | ||
867 | break; | 928 | break; |
868 | case EDID_DETAIL_STD_MODES: | 929 | case EDID_DETAIL_STD_MODES: |
869 | /* Six modes per detailed section */ | 930 | /* Six modes per detailed section */ |