kms: Fix LVDS mode list construction.
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@redhat.com>
This commit is contained in:
parent
1730af4437
commit
7d0e6ff4da
|
|
@ -695,107 +695,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;
|
||||
xf86MonPtr mon = output->MonInfo;
|
||||
|
||||
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 (!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));
|
||||
}
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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;
|
||||
}
|
||||
/* 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;
|
||||
|
||||
xf86PruneInvalidModes(output->scrn, &m, FALSE);
|
||||
|
||||
modes = xf86ModesAdd(modes, m);
|
||||
}
|
||||
|
||||
return modes;
|
||||
}
|
||||
|
||||
static DisplayModePtr
|
||||
|
|
@ -867,8 +806,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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue