diff options
author | Thomas Zimmermann <tzimmermann@suse.de> | 2020-01-23 14:59:24 +0100 |
---|---|---|
committer | Thomas Zimmermann <tzimmermann@suse.de> | 2020-02-13 13:08:13 +0100 |
commit | 7fe3f0d15aac6c98a97e6d7086f5a6b7bc4ccae4 (patch) | |
tree | ff005fcab13165c3859c8c4cdce19b181f666e26 /drivers/gpu/drm/drm_vblank.c | |
parent | drm: Add get_scanout_position() to struct drm_crtc_helper_funcs (diff) | |
download | linux-7fe3f0d15aac6c98a97e6d7086f5a6b7bc4ccae4.tar.xz linux-7fe3f0d15aac6c98a97e6d7086f5a6b7bc4ccae4.zip |
drm: Add get_vblank_timestamp() to struct drm_crtc_funcs
The callback get_vblank_timestamp() is currently located in struct
drm_driver, but really belongs into struct drm_crtc_funcs. Add an
equivalent there. Driver will be converted in separate patches.
The default implementation is drm_calc_vbltimestamp_from_scanoutpos().
The patch adds drm_crtc_vblank_helper_get_vblank_timestamp(), which is
an implementation for the CRTC callback.
v4:
* more readable code for setting high_prec (Ville, Jani)
v3:
* use refactored timestamp calculation to minimize duplicated code
* do more checks for crtc != NULL to support legacy drivers
v2:
* rename helper to drm_crtc_vblank_helper_get_vblank_timestamp()
* replace drm_calc_vbltimestamp_from_scanoutpos() with
drm_crtc_vblank_helper_get_vblank_timestamp() in docs
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200123135943.24140-4-tzimmermann@suse.de
Diffstat (limited to 'drivers/gpu/drm/drm_vblank.c')
-rw-r--r-- | drivers/gpu/drm/drm_vblank.c | 76 |
1 files changed, 67 insertions, 9 deletions
diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index 496395324d1f..cc7ef64d35f2 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -339,7 +339,9 @@ u64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc) u64 vblank; unsigned long flags; - WARN_ONCE(drm_debug_enabled(DRM_UT_VBL) && !dev->driver->get_vblank_timestamp, + WARN_ONCE(drm_debug_enabled(DRM_UT_VBL) && + !crtc->funcs->get_vblank_timestamp && + !dev->driver->get_vblank_timestamp, "This function requires support for accurate vblank timestamps."); spin_lock_irqsave(&dev->vblank_time_lock, flags); @@ -539,9 +541,9 @@ EXPORT_SYMBOL(drm_crtc_vblank_waitqueue); * * Calculate and store various constants which are later needed by vblank and * swap-completion timestamping, e.g, by - * drm_calc_vbltimestamp_from_scanoutpos(). They are derived from CRTC's true - * scanout timing, so they take things like panel scaling or other adjustments - * into account. + * drm_crtc_vblank_helper_get_vblank_timestamp(). They are derived from + * CRTC's true scanout timing, so they take things like panel scaling or + * other adjustments into account. */ void drm_calc_timestamping_constants(struct drm_crtc *crtc, const struct drm_display_mode *mode) @@ -605,8 +607,9 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants); * * Implements calculation of exact vblank timestamps from given drm_display_mode * timings and current video scanout position of a CRTC. This can be directly - * used as the &drm_driver.get_vblank_timestamp implementation of a kms driver - * if &drm_crtc_helper_funcs.get_scanout_position is implemented. + * used as the &drm_crtc_funcs.get_vblank_timestamp implementation of a kms + * driver if &drm_crtc_helper_funcs.get_scanout_position or + * &drm_driver.get_scanout_position is implemented. * * The current implementation only handles standard video modes. For double scan * and interlaced modes the driver is supposed to adjust the hardware mode @@ -803,6 +806,48 @@ drm_crtc_vblank_helper_get_vblank_timestamp_internal( EXPORT_SYMBOL(drm_crtc_vblank_helper_get_vblank_timestamp_internal); /** + * drm_crtc_vblank_helper_get_vblank_timestamp - precise vblank timestamp + * helper + * @crtc: CRTC whose vblank timestamp to retrieve + * @max_error: Desired maximum allowable error in timestamps (nanosecs) + * On return contains true maximum error of timestamp + * @vblank_time: Pointer to time which should receive the timestamp + * @in_vblank_irq: + * 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. + * + * Implements calculation of exact vblank timestamps from given drm_display_mode + * timings and current video scanout position of a CRTC. This can be directly + * used as the &drm_crtc_funcs.get_vblank_timestamp implementation of a kms + * driver if &drm_crtc_helper_funcs.get_scanout_position is implemented. + * + * The current implementation only handles standard video modes. For double scan + * and interlaced modes the driver is supposed to adjust the hardware mode + * (taken from &drm_crtc_state.adjusted mode for atomic modeset drivers) to + * match the scanout position reported. + * + * 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 + * timestamp could be acquired. + */ +bool drm_crtc_vblank_helper_get_vblank_timestamp(struct drm_crtc *crtc, + int *max_error, + ktime_t *vblank_time, + bool in_vblank_irq) +{ + return drm_crtc_vblank_helper_get_vblank_timestamp_internal( + crtc, max_error, vblank_time, in_vblank_irq, + crtc->helper_private->get_scanout_position, NULL); +} +EXPORT_SYMBOL(drm_crtc_vblank_helper_get_vblank_timestamp); + +/** * drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent * vblank interval * @dev: DRM device @@ -827,15 +872,22 @@ static bool drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe, ktime_t *tvblank, bool in_vblank_irq) { + struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); bool ret = false; /* Define requested maximum error on timestamps (nanoseconds). */ int max_error = (int) drm_timestamp_precision * 1000; /* Query driver if possible and precision timestamping enabled. */ - if (dev->driver->get_vblank_timestamp && (max_error > 0)) + if (crtc && crtc->funcs->get_vblank_timestamp && max_error > 0) { + struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); + + ret = crtc->funcs->get_vblank_timestamp(crtc, &max_error, + tvblank, in_vblank_irq); + } else if (dev->driver->get_vblank_timestamp && max_error > 0) { ret = dev->driver->get_vblank_timestamp(dev, pipe, &max_error, tvblank, in_vblank_irq); + } /* GPU high precision timestamp query unsupported or failed. * Return current monotonic/gettimeofday timestamp as best estimate. @@ -1818,6 +1870,8 @@ done: static void drm_handle_vblank_events(struct drm_device *dev, unsigned int pipe) { + struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); + bool high_prec = false; struct drm_pending_vblank_event *e, *t; ktime_t now; u64 seq; @@ -1840,8 +1894,12 @@ static void drm_handle_vblank_events(struct drm_device *dev, unsigned int pipe) send_vblank_event(dev, e, seq, now); } - trace_drm_vblank_event(pipe, seq, now, - dev->driver->get_vblank_timestamp != NULL); + if (crtc && crtc->funcs->get_vblank_timestamp) + high_prec = true; + else if (dev->driver->get_vblank_timestamp) + high_prec = true; + + trace_drm_vblank_event(pipe, seq, now, high_prec); } /** |