diff options
-rw-r--r-- | drivers/gpu/drm/drm_vblank.c | 59 | ||||
-rw-r--r-- | include/drm/drm_vblank.h | 2 |
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 | } |
1238 | EXPORT_SYMBOL(drm_crtc_vblank_on); | 1238 | EXPORT_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 | */ | ||
1250 | void 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 | } | ||
1284 | EXPORT_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 | */ | ||
1293 | void drm_crtc_vblank_restore(struct drm_crtc *crtc) | ||
1294 | { | ||
1295 | drm_vblank_restore(crtc->dev, drm_crtc_index(crtc)); | ||
1296 | } | ||
1297 | EXPORT_SYMBOL(drm_crtc_vblank_restore); | ||
1298 | |||
1240 | static void drm_legacy_vblank_pre_modeset(struct drm_device *dev, | 1299 | static 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); | |||
180 | void drm_crtc_vblank_reset(struct drm_crtc *crtc); | 180 | void drm_crtc_vblank_reset(struct drm_crtc *crtc); |
181 | void drm_crtc_vblank_on(struct drm_crtc *crtc); | 181 | void drm_crtc_vblank_on(struct drm_crtc *crtc); |
182 | u64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc); | 182 | u64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc); |
183 | void drm_vblank_restore(struct drm_device *dev, unsigned int pipe); | ||
184 | void drm_crtc_vblank_restore(struct drm_crtc *crtc); | ||
183 | 185 | ||
184 | bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, | 186 | bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, |
185 | unsigned int pipe, int *max_error, | 187 | unsigned int pipe, int *max_error, |