We have a pretty decent confusion about vertical timings of interlaced modes. Peter Ross has written a patch that makes interlace modes work on a lot more platforms/output combinations by doubling the vertical timings. The issue with that patch is that core drm _does_ support specifying whether we want these vertical timings in fields or frames, we just haven't managed to consistently use this facility. The relavant function is drm_mode_set_crtcinfo, which fills in the crtc timing information. The first thing to note is that the drm core keeps interlaced modes in frames, but displays modelines in fields. So when the crtc modeset helper copies over the mode into adjusted_mode it will already contain vertical timings in half-frames. The result is that the fixup code in intel_crtc_mode_fixup doesn't actually do anything. Now gen3+ natively supports interlaced modes and wants the vertical timings in frames. Which is what sdvo already fixes up, at least under some conditions. On gen2 we only support interlaced through dvo add-ons. The corresponding mode_fixup wants vertical timings in fields, so use that unconditionally. There are a few other place that demand vertical timings in fields but never actually deal with interlaced modes (like panels), so use frame timings for consistency, too. That leaves us with native TV out support: I honestly have no clue what this needs, but suspect that it simply ignores the pipe's timing and uses the special TV timings (which are per-field). These are programmed with fixed timing informations out of a pre-defined list of struct tv_mode. After all this we also have to fix-up the interlaced timing adjustements and substract 2 half-lines (instead of 1 with the halfed timings). According to Peter Ross, this is actually what Windows does. Patch is completely untested because I don't have a TV. So please go wild. Signed-Off-by: Daniel Vetter <daniel.vetter at ffwll.ch> --- drivers/gpu/drm/i915/intel_display.c | 35 ++++++++++++++++++--------------- drivers/gpu/drm/i915/intel_dvo.c | 1 - drivers/gpu/drm/i915/intel_overlay.c | 2 +- drivers/gpu/drm/i915/intel_panel.c | 2 +- drivers/gpu/drm/i915/intel_sdvo.c | 1 - 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index de26748..be078cb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3425,10 +3425,13 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, return false; } - /* XXX some encoders set the crtcinfo, others don't. - * Obviously we need some form of conflict resolution here... - */ - if (adjusted_mode->crtc_htotal == 0) + /* gen2 needs vertical crtc timing information in fields because that's + * what dvo outputs want - the chip itself can't do interlaced. All + * later generations can do interlaced natively and want timings in + * full frames. */ + if (IS_GEN2(dev)) + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); + else drm_mode_set_crtcinfo(adjusted_mode, 0); return true; @@ -5369,12 +5372,12 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION; /* the chip adds 2 halflines automatically */ - adjusted_mode->crtc_vdisplay -= 1; - adjusted_mode->crtc_vtotal -= 1; - adjusted_mode->crtc_vblank_start -= 1; - adjusted_mode->crtc_vblank_end -= 1; - adjusted_mode->crtc_vsync_end -= 1; - adjusted_mode->crtc_vsync_start -= 1; + adjusted_mode->crtc_vdisplay -= 2; + adjusted_mode->crtc_vtotal -= 2; + adjusted_mode->crtc_vblank_start -= 2; + adjusted_mode->crtc_vblank_end -= 2; + adjusted_mode->crtc_vsync_end -= 2; + adjusted_mode->crtc_vsync_start -= 2; } else pipeconf |= PIPECONF_PROGRESSIVE; @@ -5962,12 +5965,12 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION; /* the chip adds 2 halflines automatically */ - adjusted_mode->crtc_vdisplay -= 1; - adjusted_mode->crtc_vtotal -= 1; - adjusted_mode->crtc_vblank_start -= 1; - adjusted_mode->crtc_vblank_end -= 1; - adjusted_mode->crtc_vsync_end -= 1; - adjusted_mode->crtc_vsync_start -= 1; + adjusted_mode->crtc_vdisplay -= 2; + adjusted_mode->crtc_vtotal -= 2; + adjusted_mode->crtc_vblank_start -= 2; + adjusted_mode->crtc_vblank_end -= 2; + adjusted_mode->crtc_vsync_end -= 2; + adjusted_mode->crtc_vsync_start -= 2; } else pipeconf |= PIPECONF_PROGRESSIVE; diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 6eda1b5..020a7d7 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -157,7 +157,6 @@ static bool intel_dvo_mode_fixup(struct drm_encoder *encoder, C(vsync_end); C(vtotal); C(clock); - drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); #undef C } diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index cdf17d4..aac74ec 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -263,7 +263,7 @@ i830_activate_pipe_a(struct drm_device *dev) DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n"); mode = drm_mode_duplicate(dev, &vesa_640x480); - drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); + drm_mode_set_crtcinfo(mode, 0); if (!drm_crtc_helper_set_mode(&crtc->base, mode, crtc->base.x, crtc->base.y, crtc->base.fb)) diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index c935cda..230a141 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -48,7 +48,7 @@ intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, adjusted_mode->clock = fixed_mode->clock; - drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); + drm_mode_set_crtcinfo(adjusted_mode, 0); } /* adjusted_mode has been preset to be the panel's fixed mode */ diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index e334ec3..5b480bb 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -944,7 +944,6 @@ intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo, intel_sdvo_get_mode_from_dtd(adjusted_mode, &intel_sdvo->input_dtd); - drm_mode_set_crtcinfo(adjusted_mode, 0); return true; } -- 1.7.7.5