With the current implementation of collecting edid modes, in case rb mode exists for a non rb mode of same resolution and vrefresh, the non-rb mode is never fed to display controller to be probed, as a result we lose on using the non-rb mode, if the display controller does not support rb mode but supports non-rb.
For instance in case of 1680x1050@60Hz: with monitor whose EDID supports RB, if connected to display controller does not support 1680x1050@60Hz RB but it supports 1680x1050@60Hz, with the current implementation the non-rb mode 1680x1050@60Hz is not listed in connectors probed modes and hence on running xrandr is not listed.
V2: made drm_mode_std static
Shirish S (1): drm: edid: enable probing and listing of non rb modes
drivers/gpu/drm/drm_edid.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-)
The current solution checks for the existing RB mode, if available in the edid block returns by adding it, but does not populate the connector with the modes of same resolution but which are non-rb modes.
As a result the probing and listing of non-rb modes can't be made, in case the rb mode's pixel clock is not supported but non-rb mode is supported.
This patch changes the drm_mode_std mode selection to collect all the supported modes and not just one mode.
Signed-off-by: Shirish S s.shirish@samsung.com --- drivers/gpu/drm/drm_edid.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 8835dcd..ba865f1 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1592,12 +1592,13 @@ bad_std_timing(u8 a, u8 b) * Take the standard timing params (in this case width, aspect, and refresh) * and convert them into a real mode using CVT/GTF/DMT. */ -static struct drm_display_mode * +static unsigned int drm_mode_std(struct drm_connector *connector, struct edid *edid, struct std_timing *t, int revision) { struct drm_device *dev = connector->dev; struct drm_display_mode *m, *mode = NULL; + unsigned int modes = 0; int hsize, vsize; int vrefresh_rate; unsigned aspect_ratio = (t->vfreq_aspect & EDID_TIMING_ASPECT_MASK) @@ -1607,7 +1608,7 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid, int timing_level = standard_timing_level(edid);
if (bad_std_timing(t->hsize, t->vfreq_aspect)) - return NULL; + return modes;
/* According to the EDID spec, the hdisplay = hsize * 8 + 248 */ hsize = t->hsize * 8 + 248; @@ -1643,7 +1644,7 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid, list_for_each_entry(m, &connector->probed_modes, head) if (m->hdisplay == hsize && m->vdisplay == vsize && drm_mode_vrefresh(m) == vrefresh_rate) - return NULL; + return modes;
/* HDTV hack, part 2 */ if (hsize == 1366 && vsize == 768 && vrefresh_rate == 60) { @@ -1652,19 +1653,21 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid, mode->hdisplay = 1366; mode->hsync_start = mode->hsync_start - 1; mode->hsync_end = mode->hsync_end - 1; - return mode; + goto done; }
/* check whether it can be found in default mode table */ if (drm_monitor_supports_rb(edid)) { mode = drm_mode_find_dmt(dev, hsize, vsize, vrefresh_rate, true); - if (mode) - return mode; + if (mode) { + drm_mode_probed_add(connector, mode); + modes++; + } } mode = drm_mode_find_dmt(dev, hsize, vsize, vrefresh_rate, false); if (mode) - return mode; + goto done;
/* okay, generate it */ switch (timing_level) { @@ -1681,7 +1684,7 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid, */ mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); if (!mode) - return NULL; + return modes; if (drm_mode_hsync(mode) > drm_gtf2_hbreak(edid)) { drm_mode_destroy(dev, mode); mode = drm_gtf_mode_complex(dev, hsize, vsize, @@ -1697,7 +1700,11 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid, false); break; } - return mode; + +done: + drm_mode_probed_add(connector, mode); + return modes++; + }
/* @@ -2179,15 +2186,10 @@ do_standard_modes(struct detailed_timing *timing, void *c) int i; for (i = 0; i < 6; i++) { struct std_timing *std; - struct drm_display_mode *newmode;
std = &data->data.timings[i]; - newmode = drm_mode_std(connector, edid, std, + closure->modes += drm_mode_std(connector, edid, std, edid->revision); - if (newmode) { - drm_mode_probed_add(connector, newmode); - closure->modes++; - } } } } @@ -2208,15 +2210,10 @@ add_standard_modes(struct drm_connector *connector, struct edid *edid) };
for (i = 0; i < EDID_STD_TIMINGS; i++) { - struct drm_display_mode *newmode;
- newmode = drm_mode_std(connector, edid, + modes += drm_mode_std(connector, edid, &edid->standard_timings[i], edid->revision); - if (newmode) { - drm_mode_probed_add(connector, newmode); - modes++; - } }
if (version_greater(edid, 1, 0))
dri-devel@lists.freedesktop.org