[Intel-gfx] [PATCH] LVDS: Fix output mode list construction.
Adam Jackson
ajax at redhat.com
Tue Oct 13 21:18:31 CEST 2009
Construct a list of modes smaller than the LVDS panel size if either:
- the panel does not have EDID or DisplayID
- it has EDID/dID but does not claim to be continuous-frequency (in
which case the server would have done it for us already)
The old method would attempt to do this by mangling the EDID block and
parsed ranges, which was unreasonably fragile, and would fail to do so
when EDID existed but claimed only a single mode.
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 472bc74..d045903 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -681,107 +681,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
@@ -853,8 +792,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.4.4
More information about the Intel-gfx
mailing list