summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhao Yakui <yakui.zhao@intel.com>2009-06-10 11:17:28 +0800
committerZhenyu Wang <zhenyu.z.wang@intel.com>2009-06-16 11:27:18 +0800
commit246cec965958e94babf5377e6f221522b05fb458 (patch)
tree7d33730b368a5289bcf40d4351f97b1f981f7dd0
parent5d1dc7677004d445a7a781decd8c1ef9747c14fb (diff)
Fix EDID for LVDS output device to add the default modes
Fix the EDID for the LVDS output device to add the default modes.This is similar to what we have done in UMS mode. a. When there exists the EDID, either find the DS_RANGES block or replace a DS_VENDOR block, smashing it into a DS_RANGES block with open refresh to match all the defaults modes. b. When there is no EDID, we will construct a bogus EDID and add a DS_RANGES block with the open refresh to match all the default modes. http://bugs.freedesktop.org/show_bug.cgi?id=20801 http://bugs.freedesktop.org/show_bug.cgi?id=21094 http://bugs.freedesktop.org/show_bug.cgi?id=21346 http://bugs.freedesktop.org/show_bug.cgi?id=21417 http://bugs.freedesktop.org/show_bug.cgi?id=21671 Signed-off-by: Zhao Yakui <yakui.zhao@intel.com>
-rw-r--r--src/drmmode_display.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index aee885a0..02a71ae0 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -489,6 +489,132 @@ drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
return MODE_OK;
}
+static void fill_detailed_lvds_block(struct detailed_monitor_section *det_mon,
+ DisplayModePtr mode)
+{
+ struct detailed_timings *timing = &det_mon->section.d_timings;
+
+ det_mon->type = DT;
+ timing->clock = mode->Clock * 1000;
+ timing->h_active = mode->HDisplay;
+ timing->h_blanking = mode->HTotal - mode->HDisplay;
+ timing->v_active = mode->VDisplay;
+ timing->v_blanking = mode->VTotal - mode->VDisplay;
+ timing->h_sync_off = mode->HSyncStart - mode->HDisplay;
+ timing->h_sync_width = mode->HSyncEnd - mode->HSyncStart;
+ timing->v_sync_off = mode->VSyncStart - mode->VDisplay;
+ timing->v_sync_width = mode->VSyncEnd - mode->VSyncStart;
+
+ if (mode->Flags & V_PVSYNC)
+ timing->misc |= 0x02;
+
+ if (mode->Flags & V_PHSYNC)
+ timing->misc |= 0x01;
+}
+
+static int drmmode_output_lvds_edid(xf86OutputPtr output,
+ struct fixed_panel_lvds *p_lvds)
+{
+ 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;
+ }
+ }
+ 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;
+ }
+ /* 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;
+}
+
static DisplayModePtr
drmmode_output_get_modes(xf86OutputPtr output)
{
@@ -555,6 +681,7 @@ 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);
}
return Modes;
}