u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe);
 int amdgpu_enable_vblank_kms(struct drm_device *dev, unsigned int pipe);
 void amdgpu_disable_vblank_kms(struct drm_device *dev, unsigned int pipe);
-bool amdgpu_get_vblank_timestamp_kms(struct drm_device *dev, unsigned int pipe,
-                                    int *max_error,
-                                    struct timeval *vblank_time,
-                                    bool in_vblank_irq);
 long amdgpu_kms_compat_ioctl(struct file *filp, unsigned int cmd,
                             unsigned long arg);
 
 
 #endif
 };
 
+static bool
+amdgpu_get_crtc_scanout_position(struct drm_device *dev, unsigned int pipe,
+                                bool in_vblank_irq, int *vpos, int *hpos,
+                                ktime_t *stime, ktime_t *etime,
+                                const struct drm_display_mode *mode)
+{
+       return amdgpu_get_crtc_scanoutpos(dev, pipe, 0, vpos, hpos,
+                                         stime, etime, mode);
+}
+
 static struct drm_driver kms_driver = {
        .driver_features =
            DRIVER_USE_AGP |
        .get_vblank_counter = amdgpu_get_vblank_counter_kms,
        .enable_vblank = amdgpu_enable_vblank_kms,
        .disable_vblank = amdgpu_disable_vblank_kms,
-       .get_vblank_timestamp = amdgpu_get_vblank_timestamp_kms,
-       .get_scanout_position = amdgpu_get_crtc_scanoutpos,
+       .get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos,
+       .get_scanout_position = amdgpu_get_crtc_scanout_position,
 #if defined(CONFIG_DEBUG_FS)
        .debugfs_init = amdgpu_debugfs_init,
 #endif
 
        amdgpu_irq_put(adev, &adev->crtc_irq, idx);
 }
 
-/**
- * amdgpu_get_vblank_timestamp_kms - get vblank timestamp
- *
- * @dev: drm dev pointer
- * @crtc: crtc to get the timestamp for
- * @max_error: max error
- * @vblank_time: time value
- * @in_vblank_irq: called from drm_handle_vblank()
- *
- * Gets the timestamp on the requested crtc based on the
- * scanout position.  (all asics).
- * Returns true on success, false on failure.
- */
-bool amdgpu_get_vblank_timestamp_kms(struct drm_device *dev, unsigned int pipe,
-                                    int *max_error,
-                                    struct timeval *vblank_time,
-                                    bool in_vblank_irq)
-{
-       struct drm_crtc *crtc;
-       struct amdgpu_device *adev = dev->dev_private;
-
-       if (pipe >= dev->num_crtcs) {
-               DRM_ERROR("Invalid crtc %u\n", pipe);
-               return false;
-       }
-
-       /* Get associated drm_crtc: */
-       crtc = &adev->mode_info.crtcs[pipe]->base;
-       if (!crtc) {
-               /* This can occur on driver load if some component fails to
-                * initialize completely and driver is unloaded */
-               DRM_ERROR("Uninitialized crtc %d\n", pipe);
-               return false;
-       }
-
-       /* Helper routine in DRM core does all the work: */
-       return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
-                                                    vblank_time, in_vblank_irq,
-                                                    &crtc->hwmode);
-}
-
 const struct drm_ioctl_desc amdgpu_ioctls_kms[] = {
        DRM_IOCTL_DEF_DRV(AMDGPU_GEM_CREATE, amdgpu_gem_create_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(AMDGPU_CTX, amdgpu_ctx_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
 
                                ((em) == ATOM_ENCODER_MODE_DP_MST))
 
 /* Driver internal use only flags of amdgpu_get_crtc_scanoutpos() */
+#define DRM_SCANOUTPOS_VALID        (1 << 0)
+#define DRM_SCANOUTPOS_IN_VBLANK    (1 << 1)
+#define DRM_SCANOUTPOS_ACCURATE     (1 << 2)
 #define USE_REAL_VBLANKSTART           (1 << 30)
 #define GET_DISTANCE_TO_VBLANKSTART    (1 << 31)
 
 
 
        vblank->linedur_ns  = linedur_ns;
        vblank->framedur_ns = framedur_ns;
+       vblank->hwmode = *mode;
 
        DRM_DEBUG("crtc %u: hwmode: htotal %d, vtotal %d, vdisplay %d\n",
                  crtc->base.id, mode->crtc_htotal,
  *     True when called from drm_crtc_handle_vblank().  Some drivers
  *     need to apply some workarounds for gpu-specific vblank irq quirks
  *     if flag is set.
- * @mode: mode which defines the scanout timings
  *
  * Implements calculation of exact vblank timestamps from given drm_display_mode
  * timings and current video scanout position of a CRTC. This can be called from
  * returns as no operation if a doublescan or interlaced video mode is
  * active. Higher level code is expected to handle this.
  *
+ * This function can be used to implement the &drm_driver.get_vblank_timestamp
+ * directly, if the driver implements the &drm_driver.get_scanout_position hook.
+ *
+ * Note that atomic drivers must call drm_calc_timestamping_constants() before
+ * enabling a CRTC. The atomic helpers already take care of that in
+ * drm_atomic_helper_update_legacy_modeset_state().
+ *
  * Returns:
  *
  * Returns true on success, and false on failure, i.e. when no accurate
                                           unsigned int pipe,
                                           int *max_error,
                                           struct timeval *vblank_time,
-                                          bool in_vblank_irq,
-                                          const struct drm_display_mode *mode)
+                                          bool in_vblank_irq)
 {
        struct timeval tv_etime;
        ktime_t stime, etime;
-       unsigned int vbl_status;
+       bool vbl_status;
+       struct drm_crtc *crtc;
+       const struct drm_display_mode *mode;
+       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
        int vpos, hpos, i;
        int delta_ns, duration_ns;
-       unsigned flags = in_vblank_irq ? DRM_CALLED_FROM_VBLIRQ : 0;
 
-       if (pipe >= dev->num_crtcs) {
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return false;
+
+       crtc = drm_crtc_from_index(dev, pipe);
+
+       if (pipe >= dev->num_crtcs || !crtc) {
                DRM_ERROR("Invalid crtc %u\n", pipe);
                return false;
        }
                return false;
        }
 
+       if (drm_drv_uses_atomic_modeset(dev))
+               mode = &vblank->hwmode;
+       else
+               mode = &crtc->hwmode;
+
        /* If mode timing undefined, just return as no-op:
         * Happens during initial modesetting of a crtc.
         */
                 * Get vertical and horizontal scanout position vpos, hpos,
                 * and bounding timestamps stime, etime, pre/post query.
                 */
-               vbl_status = dev->driver->get_scanout_position(dev, pipe, flags,
+               vbl_status = dev->driver->get_scanout_position(dev, pipe,
+                                                              in_vblank_irq,
                                                               &vpos, &hpos,
                                                               &stime, &etime,
                                                               mode);
 
                /* Return as no-op if scanout query unsupported or failed. */
-               if (!(vbl_status & DRM_SCANOUTPOS_VALID)) {
-                       DRM_DEBUG("crtc %u : scanoutpos query failed [0x%x].\n",
-                                 pipe, vbl_status);
+               if (!vbl_status) {
+                       DRM_DEBUG("crtc %u : scanoutpos query failed.\n",
+                                 pipe);
                        return false;
                }
 
        etime = ktime_sub_ns(etime, delta_ns);
        *vblank_time = ktime_to_timeval(etime);
 
-       DRM_DEBUG_VBL("crtc %u : v 0x%x p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n",
-                     pipe, vbl_status, hpos, vpos,
+       DRM_DEBUG_VBL("crtc %u : v p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n",
+                     pipe, hpos, vpos,
                      (long)tv_etime.tv_sec, (long)tv_etime.tv_usec,
                      (long)vblank_time->tv_sec, (long)vblank_time->tv_usec,
                      duration_ns/1000, i);
 
        return (position + crtc->scanline_offset) % vtotal;
 }
 
-static int i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
-                                   unsigned int flags, int *vpos, int *hpos,
-                                   ktime_t *stime, ktime_t *etime,
-                                   const struct drm_display_mode *mode)
+static bool i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
+                                    bool in_vblank_irq, int *vpos, int *hpos,
+                                    ktime_t *stime, ktime_t *etime,
+                                    const struct drm_display_mode *mode)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = intel_get_crtc_for_pipe(dev_priv,
        int position;
        int vbl_start, vbl_end, hsync_start, htotal, vtotal;
        bool in_vbl = true;
-       int ret = 0;
        unsigned long irqflags;
 
        if (WARN_ON(!mode->crtc_clock)) {
                DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled "
                                 "pipe %c\n", pipe_name(pipe));
-               return 0;
+               return false;
        }
 
        htotal = mode->crtc_htotal;
                vtotal /= 2;
        }
 
-       ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
-
        /*
         * Lock uncore.lock, as we will do multiple timing critical raw
         * register reads, potentially with preemption disabled, so the
                *hpos = position - (*vpos * htotal);
        }
 
-       /* In vblank? */
-       if (in_vbl)
-               ret |= DRM_SCANOUTPOS_IN_VBLANK;
-
-       return ret;
+       return true;
 }
 
 int intel_get_crtc_scanline(struct intel_crtc *crtc)
        return position;
 }
 
-static bool i915_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe,
-                             int *max_error,
-                             struct timeval *vblank_time,
-                             bool in_vblank_irq)
-{
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_crtc *crtc;
-
-       if (pipe >= INTEL_INFO(dev_priv)->num_pipes) {
-               DRM_ERROR("Invalid crtc %u\n", pipe);
-               return false;
-       }
-
-       /* Get drm_crtc to timestamp: */
-       crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
-       if (crtc == NULL) {
-               DRM_ERROR("Invalid crtc %u\n", pipe);
-               return false;
-       }
-
-       if (!crtc->base.hwmode.crtc_clock) {
-               DRM_DEBUG_KMS("crtc %u is disabled\n", pipe);
-               return false;
-       }
-
-       /* Helper routine in DRM core does all the work: */
-       return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
-                                                    vblank_time, in_vblank_irq,
-                                                    &crtc->base.hwmode);
-}
-
 static void ironlake_rps_change_irq_handler(struct drm_i915_private *dev_priv)
 {
        u32 busy_up, busy_down, max_avg, min_avg;
 
        dev_priv->hotplug.hpd_storm_threshold = HPD_STORM_DEFAULT_THRESHOLD;
 
-       dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp;
+       dev->driver->get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos;
        dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
 
        if (IS_CHERRYVIEW(dev_priv)) {
 
        return NULL;
 }
 
-static int mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe,
-                              unsigned int flags, int *vpos, int *hpos,
-                              ktime_t *stime, ktime_t *etime,
-                              const struct drm_display_mode *mode)
+static bool mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe,
+                               bool in_vblank_irq, int *vpos, int *hpos,
+                               ktime_t *stime, ktime_t *etime,
+                               const struct drm_display_mode *mode)
 {
        struct msm_drm_private *priv = dev->dev_private;
        struct drm_crtc *crtc;
        struct drm_encoder *encoder;
        int line, vsw, vbp, vactive_start, vactive_end, vfp_end;
-       int ret = 0;
 
        crtc = priv->crtcs[pipe];
        if (!crtc) {
                DRM_ERROR("Invalid crtc %d\n", pipe);
-               return 0;
+               return false;
        }
 
        encoder = get_encoder_from_crtc(crtc);
        if (!encoder) {
                DRM_ERROR("no encoder found for crtc %d\n", pipe);
-               return 0;
+               return false;
        }
 
-       ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
-
        vsw = mode->crtc_vsync_end - mode->crtc_vsync_start;
        vbp = mode->crtc_vtotal - mode->crtc_vsync_end;
 
 
        if (line < vactive_start) {
                line -= vactive_start;
-               ret |= DRM_SCANOUTPOS_IN_VBLANK;
        } else if (line > vactive_end) {
                line = line - vfp_end - vactive_start;
-               ret |= DRM_SCANOUTPOS_IN_VBLANK;
        } else {
                line -= vactive_start;
        }
        if (etime)
                *etime = ktime_get();
 
-       return ret;
-}
-
-static bool mdp5_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe,
-                                     int *max_error,
-                                     struct timeval *vblank_time,
-                                     bool in_vblank_irq)
-{
-       struct msm_drm_private *priv = dev->dev_private;
-       struct drm_crtc *crtc;
-
-       if (pipe < 0 || pipe >= priv->num_crtcs) {
-               DRM_ERROR("Invalid crtc %d\n", pipe);
-               return false;
-       }
-
-       crtc = priv->crtcs[pipe];
-       if (!crtc) {
-               DRM_ERROR("Invalid crtc %d\n", pipe);
-               return false;
-       }
-
-       return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
-                                                    vblank_time, in_vblank_irq,
-                                                    &crtc->mode);
+       return true;
 }
 
 static u32 mdp5_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
        dev->mode_config.max_width = 0xffff;
        dev->mode_config.max_height = 0xffff;
 
-       dev->driver->get_vblank_timestamp = mdp5_get_vblank_timestamp;
+       dev->driver->get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos;
        dev->driver->get_scanout_position = mdp5_get_scanoutpos;
        dev->driver->get_vblank_counter = mdp5_get_vblank_counter;
        dev->max_vblank_count = 0xffffffff;
 
        return line;
 }
 
-static int
+static bool
 nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
                                ktime_t *stime, ktime_t *etime)
 {
        };
        struct nouveau_display *disp = nouveau_display(crtc->dev);
        struct drm_vblank_crtc *vblank = &crtc->dev->vblank[drm_crtc_index(crtc)];
-       int ret, retry = 20;
+       int retry = 20;
+       bool ret = false;
 
        do {
                ret = nvif_mthd(&disp->disp, 0, &args, sizeof(args));
                if (ret != 0)
-                       return 0;
+                       return false;
 
                if (args.scan.vline) {
-                       ret |= DRM_SCANOUTPOS_ACCURATE;
-                       ret |= DRM_SCANOUTPOS_VALID;
+                       ret = true;
                        break;
                }
 
        if (stime) *stime = ns_to_ktime(args.scan.time[0]);
        if (etime) *etime = ns_to_ktime(args.scan.time[1]);
 
-       if (*vpos < 0)
-               ret |= DRM_SCANOUTPOS_IN_VBLANK;
        return ret;
 }
 
-int
+bool
 nouveau_display_scanoutpos(struct drm_device *dev, unsigned int pipe,
-                          unsigned int flags, int *vpos, int *hpos,
+                          bool in_vblank_irq, int *vpos, int *hpos,
                           ktime_t *stime, ktime_t *etime,
                           const struct drm_display_mode *mode)
 {
                }
        }
 
-       return 0;
-}
-
-bool
-nouveau_display_vblstamp(struct drm_device *dev, unsigned int pipe,
-                        int *max_error, struct timeval *time, bool in_vblank_irq)
-{
-       struct drm_crtc *crtc;
-
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               if (nouveau_crtc(crtc)->index == pipe) {
-                       struct drm_display_mode *mode;
-                       if (drm_drv_uses_atomic_modeset(dev))
-                               mode = &crtc->state->adjusted_mode;
-                       else
-                               mode = &crtc->hwmode;
-                       return drm_calc_vbltimestamp_from_scanoutpos(dev,
-                                       pipe, max_error, time, in_vblank_irq,
-                                       mode);
-               }
-       }
-
        return false;
 }
 
 
 void nouveau_display_resume(struct drm_device *dev, bool runtime);
 int  nouveau_display_vblank_enable(struct drm_device *, unsigned int);
 void nouveau_display_vblank_disable(struct drm_device *, unsigned int);
-int  nouveau_display_scanoutpos(struct drm_device *, unsigned int,
-                               unsigned int, int *, int *, ktime_t *,
-                               ktime_t *, const struct drm_display_mode *);
-bool  nouveau_display_vblstamp(struct drm_device *, unsigned int, int *,
-                              struct timeval *, bool);
+bool  nouveau_display_scanoutpos(struct drm_device *, unsigned int,
+                                bool, int *, int *, ktime_t *,
+                                ktime_t *, const struct drm_display_mode *);
 
 int  nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                            struct drm_pending_vblank_event *event,
 
        .enable_vblank = nouveau_display_vblank_enable,
        .disable_vblank = nouveau_display_vblank_disable,
        .get_scanout_position = nouveau_display_scanoutpos,
-       .get_vblank_timestamp = nouveau_display_vblstamp,
+       .get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos,
 
        .ioctls = nouveau_ioctls,
        .num_ioctls = ARRAY_SIZE(nouveau_ioctls),
 
 u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe);
 int radeon_enable_vblank_kms(struct drm_device *dev, unsigned int pipe);
 void radeon_disable_vblank_kms(struct drm_device *dev, unsigned int pipe);
-bool radeon_get_vblank_timestamp_kms(struct drm_device *dev, unsigned int pipe,
-                                    int *max_error,
-                                    struct timeval *vblank_time,
-                                    bool in_vblank_irq);
 void radeon_driver_irq_preinstall_kms(struct drm_device *dev);
 int radeon_driver_irq_postinstall_kms(struct drm_device *dev);
 void radeon_driver_irq_uninstall_kms(struct drm_device *dev);
 #endif
 };
 
+static bool
+radeon_get_crtc_scanout_position(struct drm_device *dev, unsigned int pipe,
+                                bool in_vblank_irq, int *vpos, int *hpos,
+                                ktime_t *stime, ktime_t *etime,
+                                const struct drm_display_mode *mode)
+{
+       return radeon_get_crtc_scanoutpos(dev, pipe, 0, vpos, hpos,
+                                         stime, etime, mode);
+}
+
 static struct drm_driver kms_driver = {
        .driver_features =
            DRIVER_USE_AGP |
        .get_vblank_counter = radeon_get_vblank_counter_kms,
        .enable_vblank = radeon_enable_vblank_kms,
        .disable_vblank = radeon_disable_vblank_kms,
-       .get_vblank_timestamp = radeon_get_vblank_timestamp_kms,
-       .get_scanout_position = radeon_get_crtc_scanoutpos,
+       .get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos,
+       .get_scanout_position = radeon_get_crtc_scanout_position,
        .irq_preinstall = radeon_driver_irq_preinstall_kms,
        .irq_postinstall = radeon_driver_irq_postinstall_kms,
        .irq_uninstall = radeon_driver_irq_uninstall_kms,
 
        spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
 }
 
-/**
- * radeon_get_vblank_timestamp_kms - get vblank timestamp
- *
- * @dev: drm dev pointer
- * @crtc: crtc to get the timestamp for
- * @max_error: max error
- * @vblank_time: time value
- * @flags: flags passed to the driver
- *
- * Gets the timestamp on the requested crtc based on the
- * scanout position.  (all asics).
- * Returns true on success, false on failure.
- */
-bool radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,
-                                    int *max_error,
-                                    struct timeval *vblank_time,
-                                    bool in_vblank_irq)
-{
-       struct drm_crtc *drmcrtc;
-       struct radeon_device *rdev = dev->dev_private;
-
-       if (crtc < 0 || crtc >= dev->num_crtcs) {
-               DRM_ERROR("Invalid crtc %d\n", crtc);
-               return false;
-       }
-
-       /* Get associated drm_crtc: */
-       drmcrtc = &rdev->mode_info.crtcs[crtc]->base;
-       if (!drmcrtc)
-               return false;
-
-       /* Helper routine in DRM core does all the work: */
-       return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
-                                                    vblank_time, in_vblank_irq,
-                                                    &drmcrtc->hwmode);
-}
-
 const struct drm_ioctl_desc radeon_ioctls_kms[] = {
        DRM_IOCTL_DEF_DRV(RADEON_CP_INIT, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF_DRV(RADEON_CP_START, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 
 };
 
 /* Driver internal use only flags of radeon_get_crtc_scanoutpos() */
+#define DRM_SCANOUTPOS_VALID        (1 << 0)
+#define DRM_SCANOUTPOS_IN_VBLANK    (1 << 1)
+#define DRM_SCANOUTPOS_ACCURATE     (1 << 2)
 #define USE_REAL_VBLANKSTART           (1 << 30)
 #define GET_DISTANCE_TO_VBLANKSTART    (1 << 31)
 
 
 }
 #endif
 
-int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
-                           unsigned int flags, int *vpos, int *hpos,
-                           ktime_t *stime, ktime_t *etime,
-                           const struct drm_display_mode *mode)
+bool vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
+                            bool in_vblank_irq, int *vpos, int *hpos,
+                            ktime_t *stime, ktime_t *etime,
+                            const struct drm_display_mode *mode)
 {
        struct vc4_dev *vc4 = to_vc4_dev(dev);
        struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
        u32 val;
        int fifo_lines;
        int vblank_lines;
-       int ret = 0;
+       bool ret = false;
 
        /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
 
        fifo_lines = vc4_crtc->cob_size / mode->crtc_hdisplay;
 
        if (fifo_lines > 0)
-               ret |= DRM_SCANOUTPOS_VALID;
+               ret = true;
 
        /* HVS more than fifo_lines into frame for compositing? */
        if (*vpos > fifo_lines) {
                 */
                *vpos -= fifo_lines + 1;
 
-               ret |= DRM_SCANOUTPOS_ACCURATE;
                return ret;
        }
 
         * We can't get meaningful readings wrt. scanline position of the PV
         * and need to make things up in a approximative but consistent way.
         */
-       ret |= DRM_SCANOUTPOS_IN_VBLANK;
        vblank_lines = mode->vtotal - mode->vdisplay;
 
-       if (flags & DRM_CALLED_FROM_VBLIRQ) {
+       if (in_vblank_irq) {
                /*
                 * Assume the irq handler got called close to first
                 * line of vblank, so PV has about a full vblank
                 * we are at the very beginning of vblank, as the hvs just
                 * started refilling, and the stime and etime timestamps
                 * truly correspond to start of vblank.
+                *
+                * Unfortunately there's no way to report this to upper levels
+                * and make it more useful.
                 */
-               if ((val & SCALER_DISPSTATX_FULL) != SCALER_DISPSTATX_FULL)
-                       ret |= DRM_SCANOUTPOS_ACCURATE;
        } else {
                /*
                 * No clue where we are inside vblank. Return a vpos of zero,
        return ret;
 }
 
-bool vc4_crtc_get_vblank_timestamp(struct drm_device *dev, unsigned int crtc_id,
-                                 int *max_error, struct timeval *vblank_time,
-                                 bool in_vblank_irq)
-{
-       struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
-       struct drm_crtc_state *state = crtc->state;
-
-       /* Helper routine in DRM core does all the work: */
-       return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc_id, max_error,
-                                                    vblank_time, in_vblank_irq,
-                                                    &state->adjusted_mode);
-}
-
 static void vc4_crtc_destroy(struct drm_crtc *crtc)
 {
        drm_crtc_cleanup(crtc);
 
        .irq_uninstall = vc4_irq_uninstall,
 
        .get_scanout_position = vc4_crtc_get_scanoutpos,
-       .get_vblank_timestamp = vc4_crtc_get_vblank_timestamp,
+       .get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos,
 
 #if defined(CONFIG_DEBUG_FS)
        .debugfs_init = vc4_debugfs_init,
 
 extern struct platform_driver vc4_crtc_driver;
 bool vc4_event_pending(struct drm_crtc *crtc);
 int vc4_crtc_debugfs_regs(struct seq_file *m, void *arg);
-int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
-                           unsigned int flags, int *vpos, int *hpos,
-                           ktime_t *stime, ktime_t *etime,
-                           const struct drm_display_mode *mode);
-bool vc4_crtc_get_vblank_timestamp(struct drm_device *dev, unsigned int crtc_id,
-                                 int *max_error, struct timeval *vblank_time,
-                                 bool in_vblank_irq);
+bool vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
+                            bool in_vblank_irq, int *vpos, int *hpos,
+                            ktime_t *stime, ktime_t *etime,
+                            const struct drm_display_mode *mode);
 
 /* vc4_debugfs.c */
 int vc4_debugfs_init(struct drm_minor *minor);
 
 #define DRM_IF_VERSION(maj, min) (maj << 16 | min)
 
 
-/* Flags and return codes for get_vblank_timestamp() driver function. */
-#define DRM_CALLED_FROM_VBLIRQ 1
-
-/* get_scanout_position() return flags */
-#define DRM_SCANOUTPOS_VALID        (1 << 0)
-#define DRM_SCANOUTPOS_IN_VBLANK    (1 << 1)
-#define DRM_SCANOUTPOS_ACCURATE     (1 << 2)
-
 /**
  * DRM device structure. This structure represent a complete card that
  * may contain multiple heads.
 
         *
         * Returns:
         *
-        * Flags, or'ed together as follows:
-        *
-        * DRM_SCANOUTPOS_VALID:
-        *     Query successful.
-        * DRM_SCANOUTPOS_INVBL:
-        *     Inside vblank.
-        * DRM_SCANOUTPOS_ACCURATE: Returned position is accurate. A lack of
-        *     this flag means that returned position may be offset by a
-        *     constant but unknown small number of scanlines wrt. real scanout
-        *     position.
+        * True on success, false if a reliable scanout position counter could
+        * not be read out.
         *
         * FIXME:
         *
         * move it to &struct drm_crtc_helper_funcs, like all the other
         * helper-internal hooks.
         */
-       int (*get_scanout_position) (struct drm_device *dev, unsigned int pipe,
-                                    unsigned int flags, int *vpos, int *hpos,
-                                    ktime_t *stime, ktime_t *etime,
-                                    const struct drm_display_mode *mode);
+       bool (*get_scanout_position) (struct drm_device *dev, unsigned int pipe,
+                                     bool in_vblank_irq, int *vpos, int *hpos,
+                                     ktime_t *stime, ktime_t *etime,
+                                     const struct drm_display_mode *mode);
 
        /**
         * @get_vblank_timestamp:
 
         * drm_calc_timestamping_constants().
         */
        int linedur_ns;
+
+       /**
+        * @hwmode:
+        *
+        * Cache of the current hardware display mode. Only valid when @enabled
+        * is set. This is used by helpers like
+        * drm_calc_vbltimestamp_from_scanoutpos(). We can't just access the
+        * hardware mode by e.g. looking at &drm_crtc_state.adjusted_mode,
+        * because that one is really hard to get from interrupt context.
+        */
+       struct drm_display_mode hwmode;
+
        /**
         * @enabled: Tracks the enabling state of the corresponding &drm_crtc to
         * avoid double-disabling and hence corrupting saved state. Needed by
 bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
                                           unsigned int pipe, int *max_error,
                                           struct timeval *vblank_time,
-                                          bool in_vblank_irq,
-                                          const struct drm_display_mode *mode);
+                                          bool in_vblank_irq);
 void drm_calc_timestamping_constants(struct drm_crtc *crtc,
                                     const struct drm_display_mode *mode);