Commit a225f079 authored by Ville Syrjälä's avatar Ville Syrjälä Committed by Daniel Vetter

drm/i915: Add intel_get_crtc_scanline()

Add a new function intel_get_crtc_scanline() that returns the current
scanline counter for the crtc.

v2: Rebase after vblank timestamp changes.
    Use intel_ prefix instead of i915_ as is more customary for
    display related functions.
    Include DRM_SCANOUTPOS_INVBL in the return value even w/o
    adjustments, for a bit of extra consistency.
v3: Change the implementation to be based on DSL on all gens,
    since that's enough for the needs of atomic updates, and
    it will avoid complicating the scanout position calculations
    for the vblank timestamps
v4: Don't break scanline wraparound for interlaced modes
Reviewed-by: default avatarSourab Gupta <sourabgupta@gmail.com>
Reviewed-by: default avatarAkash Goel <akash.goels@gmail.com>
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 78e8fc6b
...@@ -751,6 +751,34 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) ...@@ -751,6 +751,34 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
/* raw reads, only for fast reads of display block, no need for forcewake etc. */ /* raw reads, only for fast reads of display block, no need for forcewake etc. */
#define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__)) #define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__))
static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
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;
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
vtotal /= 2;
if (IS_GEN2(dev))
position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN2;
else
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.
*/
return (position + 1) % vtotal;
}
static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
unsigned int flags, int *vpos, int *hpos, unsigned int flags, int *vpos, int *hpos,
ktime_t *stime, ktime_t *etime) ktime_t *stime, ktime_t *etime)
...@@ -802,20 +830,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, ...@@ -802,20 +830,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
/* No obvious pixelcount register. Only query vertical /* No obvious pixelcount register. Only query vertical
* scanout position from Display scan line register. * scanout position from Display scan line register.
*/ */
if (IS_GEN2(dev)) position = __intel_get_crtc_scanline(intel_crtc);
position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN2;
else
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.
*/
position = (position + 1) % vtotal;
} else { } else {
/* Have access to pixelcount since start of frame. /* Have access to pixelcount since start of frame.
* We can split this into vertical and horizontal * We can split this into vertical and horizontal
...@@ -876,6 +891,19 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, ...@@ -876,6 +891,19 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
return ret; return ret;
} }
int intel_get_crtc_scanline(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
unsigned long irqflags;
int position;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
position = __intel_get_crtc_scanline(crtc);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
return position;
}
static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
int *max_error, int *max_error,
struct timeval *vblank_time, struct timeval *vblank_time,
......
...@@ -653,6 +653,7 @@ void snb_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask); ...@@ -653,6 +653,7 @@ void snb_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
void snb_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask); void snb_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
void intel_runtime_pm_disable_interrupts(struct drm_device *dev); void intel_runtime_pm_disable_interrupts(struct drm_device *dev);
void intel_runtime_pm_restore_interrupts(struct drm_device *dev); void intel_runtime_pm_restore_interrupts(struct drm_device *dev);
int intel_get_crtc_scanline(struct intel_crtc *crtc);
/* intel_crt.c */ /* intel_crt.c */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment