[Intel-gfx] [PATCH 1/5] drm/i915: Fix scanout position for real
Ville Syrjälä
ville.syrjala at linux.intel.com
Tue Apr 1 12:36:17 CEST 2014
On Fri, Mar 14, 2014 at 11:46:35AM +0530, akash goel wrote:
> Hi,
>
> We have reviewed the patch & overall it seems to be fine.
> Although this patch has really simplified the scan-out calculation, but
> we do have few doubts/opens.
>
> There is a particular change :-
>
>
>
> *position = (position + htotal - hsync_start) % vtotal;*
>
>
> This adjustment could although lead to more accurate estimation of 'Vblank'
> interval, but will compromise with the accuracy of 'hpos'.
> Should we be avoiding the latter & preserve the original value of 'hpos'
> returned by pixel counter ?
Everyone more or less assumes that the start of vblank is when stuff
happens, and that the start of vblank happens at the start of horizontal
active. So I think we should keep the in_vblank status and position
consistent with that notion and accept the small error we get as a
result.
>
> Also we couldn't fully understand the comments related to Scanline counter
> increment in the commit message & under the 'if (HAS_PCH_SPLIT(dev))' condition
> in the code.
> What we understood is that the scanline counter will increment on a Hsync
> pulse & when the first active line is being scanned, the counter will
> return '0' .
>
> When the 2nd second active line is being scanned, counter will
> return '1'. Assuming if there are 10 active lines, so when the last active
> line is being scanned, the scan line counter will return 9, but on the
> Hsync pulse of the last active line (which will mark the start of
> vblank interval also),
> counter will increment to 10. And the counter should wraparound to 0, when
> last line ('vtotal') has been scanned completely.
>
> Please could you let us know that if there are 10 active lines, the value
> of 'vbl_start' will be 10 or 11 ? Actually we are bit confused that
> whether zero based indexing is being used here or not. Ideally the 'hpos' &
> 'vpos' shall be calculated with zero based indexing.
In theory the scanline counter should be 0 on the first active line
(the counter is 0 based). But the hardware is weird and the scanline
counter will actually read either 1 or vtotal-1 on the first active line
(or even vtotal-2 in some cases, and so far no one seems to know why that
is). So the best I've been able to do figure out the rules via empirical
experiments.
>
>
> Sorry but as of now, we mainly have understanding & visibility from GEN7 Hw
> onwards, so we could review the patches from >= GEN7 perspective only.
>
> Best Regards
> Akash
>
>
> On Thu, Feb 13, 2014 at 9:12 PM, <ville.syrjala at linux.intel.com> wrote:
>
> > From: Ville Syrjälä <ville.syrjala at linux.intel.com>
> >
> > Seems I've been a bit dense with regards to the start of vblank
> > vs. the scanline counter / pixel counter.
> >
> > After staring at the pixel counter on gen4 I came to the conclusion
> > that the start of vblank interrupt and scanline counter increment
> > happen at the same time. The scanline counter increment is documented
> > to occur at start of hsync, which means that the start of vblank
> > interrupt must also trigger there. Looking at the pixel counter value
> > when the scanline wraps from vtotal-1 to 0 confirms that, as the pixel
> > counter at that point reads hsync_start. This also clarifies why we see
> > need the +1 adjustment to the scaline counter. The counter actually
> > starts counting from vtotal-1 on the first active line.
> >
> > I also confirmed that the frame start interrupt happens ~1 line after
> > the start of vblank, but the frame start occurs at hblank_start instead.
> > We only use the frame start interrupt on gen2 where the start of vblank
> > interrupt isn't available. The only important thing to note here is that
> > frame start occurs after vblank start, so we don't have to play any
> > additional tricks to fix up the scanline counter.
> >
> > The other thing to note is the fact that the pixel counter on gen3-4
> > starts counting from the start of horizontal active on the first active
> > line. That means that when we get the start of vblank interrupt, the
> > pixel counter reads (htotal*(vblank_start-1)+hsync_start). Since we
> > consider vblank to start at (htotal*vblank_start) we need to add a
> > constant (htotal-hsync_start) offset to the pixel counter, or else we
> > risk misdetecting whether we're in vblank or not.
> >
> > I talked a bit with Art Runyan about these topics, and he confirmed my
> > findings. And that the same rules should hold for platforms which don't
> > have the pixel counter. That's good since without the pixel counter it's
> > rather difficult to verify the timings to this accuracy.
> >
> > So the conclusion is that we can throw away all the ISR tricks I added,
> > and just increment the scanline counter by one always.
> >
> > Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
> > ---
> > drivers/gpu/drm/i915/i915_irq.c | 89
> > +++++++++++------------------------------
> > 1 file changed, 23 insertions(+), 66 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/i915_irq.c
> > b/drivers/gpu/drm/i915/i915_irq.c
> > index f68aee3..d547994 100644
> > --- a/drivers/gpu/drm/i915/i915_irq.c
> > +++ b/drivers/gpu/drm/i915/i915_irq.c
> > @@ -706,34 +706,6 @@ 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. */
> > #define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs +
> > (reg__))
> > -#define __raw_i915_read16(dev_priv__, reg__) readw((dev_priv__)->regs +
> > (reg__))
> > -
> > -static bool ilk_pipe_in_vblank_locked(struct drm_device *dev, enum pipe
> > pipe)
> > -{
> > - struct drm_i915_private *dev_priv = dev->dev_private;
> > - uint32_t status;
> > -
> > - if (INTEL_INFO(dev)->gen < 7) {
> > - status = pipe == PIPE_A ?
> > - DE_PIPEA_VBLANK :
> > - DE_PIPEB_VBLANK;
> > - } else {
> > - switch (pipe) {
> > - default:
> > - case PIPE_A:
> > - status = DE_PIPEA_VBLANK_IVB;
> > - break;
> > - case PIPE_B:
> > - status = DE_PIPEB_VBLANK_IVB;
> > - break;
> > - case PIPE_C:
> > - status = DE_PIPEC_VBLANK_IVB;
> > - break;
> > - }
> > - }
> > -
> > - return __raw_i915_read32(dev_priv, DEISR) & status;
> > -}
> >
> > static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
> > unsigned int flags, int *vpos, int
> > *hpos,
> > @@ -744,7 +716,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device
> > *dev, int pipe,
> > struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> > const struct drm_display_mode *mode =
> > &intel_crtc->config.adjusted_mode;
> > int position;
> > - int vbl_start, vbl_end, htotal, vtotal;
> > + int vbl_start, vbl_end, hsync_start, htotal, vtotal;
> > bool in_vbl = true;
> > int ret = 0;
> > unsigned long irqflags;
> > @@ -756,6 +728,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device
> > *dev, int pipe,
> > }
> >
> > htotal = mode->crtc_htotal;
> > + hsync_start = mode->crtc_hsync_start;
> > vtotal = mode->crtc_vtotal;
> > vbl_start = mode->crtc_vblank_start;
> > vbl_end = mode->crtc_vblank_end;
> > @@ -774,7 +747,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device
> > *dev, int pipe,
> > * following code must not block on uncore.lock.
> > */
> > spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
> > -
> > +
> > /* preempt_disable_rt() should go right here in PREEMPT_RT
> > patchset. */
> >
> > /* Get optional system timestamp before query. */
> > @@ -790,42 +763,15 @@ static int i915_get_crtc_scanoutpos(struct
> > drm_device *dev, int pipe,
> > else
> > position = __raw_i915_read32(dev_priv,
> > PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
> >
> > - if (HAS_PCH_SPLIT(dev)) {
> > - /*
> > - * The scanline counter increments at the leading
> > edge
> > - * of hsync, ie. it completely misses the active
> > portion
> > - * of the line. Fix up the counter at both edges
> > of vblank
> > - * to get a more accurate picture whether we're in
> > vblank
> > - * or not.
> > - */
> > - in_vbl = ilk_pipe_in_vblank_locked(dev, pipe);
> > - if ((in_vbl && position == vbl_start - 1) ||
> > - (!in_vbl && position == vbl_end - 1))
> > - position = (position + 1) % vtotal;
> > - } else {
> > - /*
> > - * ISR vblank status bits don't work the way we'd
> > want
> > - * them to work on non-PCH platforms (for
> > - * ilk_pipe_in_vblank_locked()), and there doesn't
> > - * appear any other way to determine if we're
> > currently
> > - * in vblank.
> > - *
> > - * Instead let's assume that we're already in
> > vblank if
> > - * we got called from the vblank interrupt and the
> > - * scanline counter value indicates that we're on
> > the
> > - * line just prior to vblank start. This should
> > result
> > - * in the correct answer, unless the vblank
> > interrupt
> > - * delivery really got delayed for almost exactly
> > one
> > - * full frame/field.
> > - */
> > - if (flags & DRM_CALLED_FROM_VBLIRQ &&
> > - position == vbl_start - 1) {
> > - position = (position + 1) % vtotal;
> > -
> > - /* Signal this correction as "applied". */
> > - ret |= 0x8;
> > - }
> > - }
> > + /*
> > + * 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 {
> > /* Have access to pixelcount since start of frame.
> > * We can split this into vertical and horizontal
> > @@ -837,6 +783,17 @@ static int i915_get_crtc_scanoutpos(struct drm_device
> > *dev, int pipe,
> > vbl_start *= htotal;
> > vbl_end *= htotal;
> > vtotal *= htotal;
> > +
> > + /*
> > + * Start of vblank interrupt is triggered at start of
> > hsync,
> > + * just prior to the first active line of vblank. However
> > we
> > + * consider lines to start at the leading edge of
> > horizontal
> > + * active. So, should we get here before we've crossed into
> > + * the horizontal active of the first line in vblank, we
> > would
> > + * not set the DRM_SCANOUTPOS_INVBL flag. In order to fix
> > that,
> > + * always add htotal-hsync_start to the current pixel
> > position.
> > + */
> > + position = (position + htotal - hsync_start) % vtotal;
> > }
> >
> > /* Get optional system timestamp after query. */
> > --
> > 1.8.3.2
> >
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx at lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
> >
--
Ville Syrjälä
Intel OTC
More information about the Intel-gfx
mailing list