aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/drm_vblank.c59
-rw-r--r--include/drm/drm_vblank.h2
2 files changed, 61 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
index 913954765d9e..c781cb426bf1 100644
--- a/drivers/gpu/drm/drm_vblank.c
+++ b/drivers/gpu/drm/drm_vblank.c
@@ -1237,6 +1237,65 @@ void drm_crtc_vblank_on(struct drm_crtc *crtc)
1237} 1237}
1238EXPORT_SYMBOL(drm_crtc_vblank_on); 1238EXPORT_SYMBOL(drm_crtc_vblank_on);
1239 1239
1240/**
1241 * drm_vblank_restore - estimated vblanks using timestamps and update it.
1242 *
1243 * Power manamement features can cause frame counter resets between vblank
1244 * disable and enable. Drivers can then use this function in their
1245 * &drm_crtc_funcs.enable_vblank implementation to estimate the vblanks since
1246 * the last &drm_crtc_funcs.disable_vblank.
1247 *
1248 * This function is the legacy version of drm_crtc_vblank_restore().
1249 */
1250void drm_vblank_restore(struct drm_device *dev, unsigned int pipe)
1251{
1252 ktime_t t_vblank;
1253 struct drm_vblank_crtc *vblank;
1254 int framedur_ns;
1255 u64 diff_ns;
1256 u32 cur_vblank, diff = 1;
1257 int count = DRM_TIMESTAMP_MAXRETRIES;
1258
1259 if (WARN_ON(pipe >= dev->num_crtcs))
1260 return;
1261
1262 assert_spin_locked(&dev->vbl_lock);
1263 assert_spin_locked(&dev->vblank_time_lock);
1264
1265 vblank = &dev->vblank[pipe];
1266 WARN_ONCE((drm_debug & DRM_UT_VBL) && !vblank->framedur_ns,
1267 "Cannot compute missed vblanks without frame duration\n");
1268 framedur_ns = vblank->framedur_ns;
1269
1270 do {
1271 cur_vblank = __get_vblank_counter(dev, pipe);
1272 drm_get_last_vbltimestamp(dev, pipe, &t_vblank, false);
1273 } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
1274
1275 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
1276 if (framedur_ns)
1277 diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns);
1278
1279
1280 DRM_DEBUG_VBL("missed %d vblanks in %lld ns, frame duration=%d ns, hw_diff=%d\n",
1281 diff, diff_ns, framedur_ns, cur_vblank - vblank->last);
1282 store_vblank(dev, pipe, diff, t_vblank, cur_vblank);
1283}
1284EXPORT_SYMBOL(drm_vblank_restore);
1285
1286/**
1287 * drm_crtc_vblank_restore - estimate vblanks using timestamps and update it.
1288 * Power manamement features can cause frame counter resets between vblank
1289 * disable and enable. Drivers can then use this function in their
1290 * &drm_crtc_funcs.enable_vblank implementation to estimate the vblanks since
1291 * the last &drm_crtc_funcs.disable_vblank.
1292 */
1293void drm_crtc_vblank_restore(struct drm_crtc *crtc)
1294{
1295 drm_vblank_restore(crtc->dev, drm_crtc_index(crtc));
1296}
1297EXPORT_SYMBOL(drm_crtc_vblank_restore);
1298
1240static void drm_legacy_vblank_pre_modeset(struct drm_device *dev, 1299static void drm_legacy_vblank_pre_modeset(struct drm_device *dev,
1241 unsigned int pipe) 1300 unsigned int pipe)
1242{ 1301{
diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h
index a4c3b0a0a197..16d46e2a6854 100644
--- a/include/drm/drm_vblank.h
+++ b/include/drm/drm_vblank.h
@@ -180,6 +180,8 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc);
180void drm_crtc_vblank_reset(struct drm_crtc *crtc); 180void drm_crtc_vblank_reset(struct drm_crtc *crtc);
181void drm_crtc_vblank_on(struct drm_crtc *crtc); 181void drm_crtc_vblank_on(struct drm_crtc *crtc);
182u64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc); 182u64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc);
183void drm_vblank_restore(struct drm_device *dev, unsigned int pipe);
184void drm_crtc_vblank_restore(struct drm_crtc *crtc);
183 185
184bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, 186bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
185 unsigned int pipe, int *max_error, 187 unsigned int pipe, int *max_error,