[Intel-gfx] [PATCH] kms: Fix LVDS mode list construction.
Adam Jackson
ajax at redhat.com
Wed Dec 2 18:05:52 CET 2009
Rather than mangle the EDID block and hope the server does the right
thing, just build a sensible mode list up front. Do this for LVDS where
there is no EDID or where it does not claim to be continuous-frequency
(since in the latter case, the server will add reasonable modes for us).
Signed-off-by: Adam Jackson <ajax at redhat.com>
---
src/drmmode_display.c | 140 ++++++++++++++----------------------------------
1 files changed, 41 insertions(+), 99 deletions(-)
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index a469f6c..d5e3c7e 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -682,107 +682,46 @@ static void fill_detailed_lvds_block(struct detailed_monitor_section *det_mon,
timing->misc |= 0x01;
}
-static int drmmode_output_lvds_edid(xf86OutputPtr output,
- struct fixed_panel_lvds *p_lvds)
+static DisplayModePtr
+drmmode_output_lvds_edid(xf86OutputPtr output, DisplayModePtr modes)
{
- drmmode_output_private_ptr drmmode_output = output->driver_private;
- drmModeConnectorPtr koutput = drmmode_output->mode_output;
- int i, j;
- DisplayModePtr pmode;
- xf86MonPtr edid_mon;
- drmModeModeInfo *mode_ptr;
- struct detailed_monitor_section *det_mon;
-
- if (output->MonInfo) {
- /*
- * If there exists the EDID, we will either find a DS_RANGES
- * or replace a DS_VENDOR block, smashing it into a DS_RANGES
- * block with opern refresh to match all the default modes.
- */
- int edid_det_block_num;
- edid_mon = output->MonInfo;
- edid_mon->features.msc |= 0x01;
- j = -1;
- edid_det_block_num = sizeof(edid_mon->det_mon) /
- sizeof(edid_mon->det_mon[0]);
- for (i = 0; i < edid_det_block_num; i++) {
- if (edid_mon->det_mon[i].type >= DS_VENDOR && j == -1)
- j = i;
- if (edid_mon->det_mon[i].type == DS_RANGES) {
- j = i;
- break;
- }
- }
- if (j != -1) {
- struct monitor_ranges *ranges =
- &edid_mon->det_mon[j].section.ranges;
- edid_mon->det_mon[j].type = DS_RANGES;
- ranges->min_v = 0;
- ranges->max_v = 200;
- ranges->min_h = 0;
- ranges->max_h = 200;
- }
- return 0;
- }
- /*
- * If there is no EDID, we will construct a bogus EDID for LVDS output
- * device. This is similar to what we have done in i830_lvds.c
- */
- edid_mon = NULL;
- edid_mon = xcalloc(1, sizeof(xf86Monitor));
- if (!edid_mon) {
- xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
- "Can't allocate memory for edid_mon.\n");
- return 0;
- }
- /* Find the fixed panel mode.
- * In theory when there is no EDID, KMS kernel will return only one
- * mode. And this can be regarded as fixed lvds panel mode.
- * But it will be better to traverse the mode list to get the fixed
- * lvds panel mode again as we don't know whether some new modes
- * are added for the LVDS output device
- */
- j = 0;
- for (i = 0; i < koutput->count_modes; i++) {
- mode_ptr = &koutput->modes[i];
- if ((mode_ptr->hdisplay == p_lvds->hdisplay) &&
- (mode_ptr->vdisplay == p_lvds->vdisplay)) {
- /* find the fixed panel mode */
- j = i;
- break;
- }
+ xf86MonPtr mon = output->MonInfo;
+
+ if (!mon || !GTF_SUPPORTED(mon->features.msc)) {
+ DisplayModePtr i, m, p = NULL;
+ int max_x = 0, max_y = 0;
+ float max_vrefresh = 0.0;
+
+ for (m = modes; m; m = m->next) {
+ if (m->type & M_T_PREFERRED)
+ p = m;
+ max_x = max(max_x, m->HDisplay);
+ max_y = max(max_y, m->VDisplay);
+ max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(m));
}
- pmode = xnfalloc(sizeof(DisplayModeRec));
- drmmode_ConvertFromKMode(output->scrn, &koutput->modes[j], pmode);
- /*support DPM, instead of DPMS*/
- edid_mon->features.dpms |= 0x1;
- /*defaultly support RGB color display*/
- edid_mon->features.display_type |= 0x1;
- /*defaultly display support continuous-freqencey*/
- edid_mon->features.msc |= 0x1;
- /*defaultly the EDID version is 1.4 */
- edid_mon->ver.version = 1;
- edid_mon->ver.revision = 4;
- det_mon = edid_mon->det_mon;
- if (pmode) {
- /* now we construct new EDID monitor,
- * so filled one detailed timing block
- */
- fill_detailed_lvds_block(det_mon, pmode);
- /* the filed timing block should be set preferred*/
- edid_mon->features.msc |= 0x2;
- det_mon = det_mon + 1;
+
+ max_vrefresh = max(max_vrefresh, 60.0);
+ max_vrefresh *= (1 + SYNC_TOLERANCE);
+
+ m = xf86GetDefaultModes();
+
+ xf86ValidateModesSize(output->scrn, m, max_x, max_y, 0);
+
+ for (i = m; i; i = i->next) {
+ if (xf86ModeVRefresh(i) > max_vrefresh)
+ i->status = MODE_VSYNC;
+ if (p && i->HDisplay >= p->HDisplay &&
+ i->VDisplay >= p->VDisplay &&
+ xf86ModeVRefresh(i) >= xf86ModeVRefresh(p))
+ i->status = MODE_VSYNC;
}
- /* Set wide sync ranges so we get all modes
- * handed to valid_mode for checking
- */
- det_mon->type = DS_RANGES;
- det_mon->section.ranges.min_v = 0;
- det_mon->section.ranges.max_v = 200;
- det_mon->section.ranges.min_h = 0;
- det_mon->section.ranges.max_h = 200;
- output->MonInfo = edid_mon;
- return 0;
+
+ xf86PruneInvalidModes(output->scrn, &m, FALSE);
+
+ modes = xf86ModesAdd(modes, m);
+ }
+
+ return modes;
}
static DisplayModePtr
@@ -854,8 +793,11 @@ drmmode_output_get_modes(xf86OutputPtr output)
if (!p_lvds->hdisplay || !p_lvds->vdisplay)
xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
"Incorrect KMS mode.\n");
- drmmode_output_lvds_edid(output, p_lvds);
}
+
+ if (koutput->connector_type == DRM_MODE_CONNECTOR_LVDS)
+ Modes = drmmode_output_lvds_edid(output, Modes);
+
return Modes;
}
--
1.6.5.2
More information about the Intel-gfx
mailing list