diff options
author | Adam Jackson <ajax@redhat.com> | 2012-04-14 00:33:40 +0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2012-04-20 15:57:56 +0400 |
commit | b309bd37a1357bd4391dace247cceb9d9121d20a (patch) | |
tree | 0ac7b559daea685fe8a5b1fbab1209708de7a27b | |
parent | b61b2140feaa6aca51c63db94aa5217cd82705d1 (diff) | |
download | linux-b309bd37a1357bd4391dace247cceb9d9121d20a.tar.xz |
drm/edid: Generate modes from extra_modes for range descriptors
Signed-off-by: Adam Jackson <ajax@redhat.com>
Tested-by: Takashi Iwai <tiwai@suse.de>
Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 9363349fa034..38ee2f22304c 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1037,11 +1037,61 @@ drm_dmt_modes_for_range(struct drm_connector *connector, struct edid *edid, return modes; } +static int +drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid, + struct detailed_timing *timing) +{ + int i, modes = 0; + struct drm_display_mode *newmode; + struct drm_device *dev = connector->dev; + + for (i = 0; i < num_extra_modes; i++) { + const struct minimode *m = &extra_modes[i]; + newmode = drm_gtf_mode(dev, m->w, m->h, m->r, 0, 0); + + if (!mode_in_range(newmode, edid, timing)) { + drm_mode_destroy(dev, newmode); + continue; + } + + drm_mode_probed_add(connector, newmode); + modes++; + } + + return modes; +} + +static int +drm_cvt_modes_for_range(struct drm_connector *connector, struct edid *edid, + struct detailed_timing *timing) +{ + int i, modes = 0; + struct drm_display_mode *newmode; + struct drm_device *dev = connector->dev; + bool rb = drm_monitor_supports_rb(edid); + + for (i = 0; i < num_extra_modes; i++) { + const struct minimode *m = &extra_modes[i]; + newmode = drm_cvt_mode(dev, m->w, m->h, m->r, rb, 0, 0); + + if (!mode_in_range(newmode, edid, timing)) { + drm_mode_destroy(dev, newmode); + continue; + } + + drm_mode_probed_add(connector, newmode); + modes++; + } + + return modes; +} + static void do_inferred_modes(struct detailed_timing *timing, void *c) { struct detailed_mode_closure *closure = c; struct detailed_non_pixel *data = &timing->data.other_data; + struct detailed_data_monitor_range *range = &data->data.range; if (data->type != EDID_DETAIL_MONITOR_RANGE) return; @@ -1049,6 +1099,29 @@ do_inferred_modes(struct detailed_timing *timing, void *c) closure->modes += drm_dmt_modes_for_range(closure->connector, closure->edid, timing); + + if (!version_greater(closure->edid, 1, 1)) + return; /* GTF not defined yet */ + + switch (range->flags) { + case 0x02: /* secondary gtf, XXX could do more */ + case 0x00: /* default gtf */ + closure->modes += drm_gtf_modes_for_range(closure->connector, + closure->edid, + timing); + break; + case 0x04: /* cvt, only in 1.4+ */ + if (!version_greater(closure->edid, 1, 3)) + break; + + closure->modes += drm_cvt_modes_for_range(closure->connector, + closure->edid, + timing); + break; + case 0x01: /* just the ranges, no formula */ + default: + break; + } } static int |