[Intel-gfx] [PATCH] LVDS: Fix output mode list construction.

Dave Airlie airlied at gmail.com
Tue Oct 13 22:36:24 CEST 2009


On Wed, Oct 14, 2009 at 5:18 AM, Adam Jackson <ajax at redhat.com> wrote:
> 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.

This really should be done in the kernel from what I can see, so all KMS users
get a consistent list of modes for the LVDS device.

Dave.

>
> 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
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>



More information about the Intel-gfx mailing list