From: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> On gen2 the scanline counter behaves a bit differently from the later generations. Instead of adding one to the raw scanline counter value, we must subtract one. On HSW the scanline counter apparently requires a +2 adjustment on HDMI outputs. eDP on port A however wants the +1 adjustment. So far no one has tested DP/eDP on port != A, and also BDW behaviour is still a mystery. As the fixup we must apply to the hardware scanline counter depends on several factors, compute the desired offset at modeset time and tuck it away for when it's needed. Signed-off-by: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> --- drivers/gpu/drm/i915/i915_irq.c | 14 ++++------- drivers/gpu/drm/i915/intel_display.c | 48 +++++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_drv.h | 2 ++ 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index bc4585b..8e1b104 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -817,9 +817,9 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; const struct drm_display_mode *mode = &crtc->config.adjusted_mode; enum pipe pipe = crtc->pipe; - int vtotal = mode->crtc_vtotal; - int position; + int position, vtotal; + vtotal = mode->crtc_vtotal; if (mode->flags & DRM_MODE_FLAG_INTERLACE) vtotal /= 2; @@ -829,14 +829,10 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc) position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3; /* - * Scanline counter increments at leading edge of hsync, and - * it starts counting from vtotal-1 on the first active line. - * That means the scanline counter value is always one less - * than what we would expect. Ie. just after start of vblank, - * which also occurs at start of hsync (on the last active line), - * the scanline counter will read vblank_start-1. + * See update_scanline_offset() for the details on the + * scanline_offset adjustment. */ - return (position + 1) % vtotal; + return (position + crtc->scanline_offset) % vtotal; } static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 993597b..93ef06b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9886,6 +9886,47 @@ void ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config pipe_config->adjusted_mode.crtc_clock, dotclock); } +static void update_scanline_offset(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + + /* + * The scanline counter increments at the leading edge of hsync. + * + * On most platforms it starts counting from vtotal-1 on the + * first active line. That means the scanline counter value is + * always one less than what we would expect. Ie. just after + * start of vblank, which also occurs at start of hsync (on the + * last active line), the scanline counter will read vblank_start-1. + * + * On gen2 the scanline counter starts counting from 1 instead + * of vtotal-1, so we have to subtract one (or rather add vtotal-1 + * to keep the value positive), instead of adding one. + * + * On HSW the behaviour of the scanline counter depends either on + * the output type, or the DDI port used (so far it's unclear which). + * In certain cases we need to add 2 instead of 1 to the reported + * scanline counter value. + * FIXME: +2 seems to be correct for HDMI, but eDP on port A wants +1 + * instead. Not sure how DP on other ports behaves. + * FIXME: How does BDW behave? + */ + if (IS_GEN2(dev)) { + const struct drm_display_mode *mode = &crtc->config.adjusted_mode; + int vtotal; + + vtotal = mode->crtc_vtotal; + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + vtotal /= 2; + + crtc->scanline_offset = vtotal - 1; + } else if (HAS_DDI(dev) && + intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI)) { + crtc->scanline_offset = 2; + } else + crtc->scanline_offset = 1; +} + static int __intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *fb) @@ -9984,8 +10025,11 @@ static int __intel_set_mode(struct drm_crtc *crtc, } /* Now enable the clocks, plane, pipe, and connectors that we set up. */ - for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) + for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) { + update_scanline_offset(intel_crtc); + dev_priv->display.crtc_enable(&intel_crtc->base); + } /* FIXME: add subpixel order */ done: @@ -11511,6 +11555,8 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) */ crtc->cpu_fifo_underrun_disabled = true; crtc->pch_fifo_underrun_disabled = true; + + update_scanline_offset(crtc); } } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d8b540b..5420368 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -403,6 +403,8 @@ struct intel_crtc { } wm; wait_queue_head_t vbl_wait; + + int scanline_offset; }; struct intel_plane_wm_parameters { -- 1.8.3.2 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx