@@ -1230,6 +1230,36 @@ void drm_crtc_vblank_on(struct drm_crtc *crtc)
}
EXPORT_SYMBOL(drm_crtc_vblank_on);
+void drm_crtc_vblank_restore(struct drm_device *dev, unsigned int pipe)
+{
+ ktime_t t_vblank;
+ struct drm_vblank_crtc *vblank;
+ int framedur_ns;
+ u64 diff_ns;
+ u32 cur_vblank, diff = 1;
+ int count = DRM_TIMESTAMP_MAXRETRIES;
+
+ if (WARN_ON(pipe >= dev->num_crtcs))
+ return;
+
+ vblank = &dev->vblank[pipe];
+ framedur_ns = vblank->framedur_ns;
+
+ do {
+ cur_vblank = __get_vblank_counter(dev, pipe);
+ drm_get_last_vbltimestamp(dev, pipe, &t_vblank, false);
+ } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
+
+ diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
+ if (framedur_ns)
+ diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns);
+
+ DRM_DEBUG_VBL("computing missed vblanks %lld/%d=%d after HW counter reset hw_diff=%d\n",
+ diff_ns, framedur_ns, diff, cur_vblank - vblank->last);
+ store_vblank(dev, pipe, diff, t_vblank, cur_vblank);
+}
+EXPORT_SYMBOL(drm_crtc_vblank_restore);
+
static void drm_legacy_vblank_pre_modeset(struct drm_device *dev,
unsigned int pipe)
{
@@ -180,6 +180,7 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc);
void drm_crtc_vblank_reset(struct drm_crtc *crtc);
void drm_crtc_vblank_on(struct drm_crtc *crtc);
u32 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc);
+void drm_crtc_vblank_restore(struct drm_device *dev, unsigned int pipe);
bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
unsigned int pipe, int *max_error,
The HW frame counter can get reset when devices enters low power states and this messes up any following vblank count updates. So, compute the missed vblank interrupts for that low power state duration using time stamps. This is similar to _crtc_vblank_on() except that it doesn't enable vblank interrupts because this function is expected to be called from the driver _enable_vblank() vfunc. Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> --- drivers/gpu/drm/drm_vblank.c | 30 ++++++++++++++++++++++++++++++ include/drm/drm_vblank.h | 1 + 2 files changed, 31 insertions(+)