mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 14:12:06 +00:00
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
This commit is contained in:
parent
f1e2b6371c
commit
7fe3f0d15a
@ -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
|
||||
@ -802,6 +805,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
|
||||
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -887,6 +887,47 @@ struct drm_crtc_funcs {
|
||||
* new drivers as the replacement of &drm_driver.disable_vblank hook.
|
||||
*/
|
||||
void (*disable_vblank)(struct drm_crtc *crtc);
|
||||
|
||||
/**
|
||||
* @get_vblank_timestamp:
|
||||
*
|
||||
* Called by drm_get_last_vbltimestamp(). Should return a precise
|
||||
* timestamp when the most recent vblank interval ended or will end.
|
||||
*
|
||||
* Specifically, the timestamp in @vblank_time should correspond as
|
||||
* closely as possible to the time when the first video scanline of
|
||||
* the video frame after the end of vblank will start scanning out,
|
||||
* the time immediately after end of the vblank interval. If the
|
||||
* @crtc is currently inside vblank, this will be a time in the future.
|
||||
* If the @crtc is currently scanning out a frame, this will be the
|
||||
* past start time of the current scanout. This is meant to adhere
|
||||
* to the OpenML OML_sync_control extension specification.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* crtc:
|
||||
* CRTC for which timestamp should be returned.
|
||||
* max_error:
|
||||
* Maximum allowable timestamp error in nanoseconds.
|
||||
* Implementation should strive to provide timestamp
|
||||
* with an error of at most max_error nanoseconds.
|
||||
* Returns true upper bound on error for timestamp.
|
||||
* vblank_time:
|
||||
* Target location for returned vblank 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.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* True on success, false on failure, which means the core should
|
||||
* fallback to a simple timestamp taken in drm_crtc_handle_vblank().
|
||||
*/
|
||||
bool (*get_vblank_timestamp)(struct drm_crtc *crtc,
|
||||
int *max_error,
|
||||
ktime_t *vblank_time,
|
||||
bool in_vblank_irq);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -994,11 +1035,12 @@ struct drm_crtc {
|
||||
* Programmed mode in hw, after adjustments for encoders, crtc, panel
|
||||
* scaling etc. Should only be used by legacy drivers, for high
|
||||
* precision vblank timestamps in
|
||||
* drm_calc_vbltimestamp_from_scanoutpos().
|
||||
* drm_crtc_vblank_helper_get_vblank_timestamp().
|
||||
*
|
||||
* Note that atomic drivers should not use this, but instead use
|
||||
* &drm_crtc_state.adjusted_mode. And for high-precision timestamps
|
||||
* drm_calc_vbltimestamp_from_scanoutpos() used &drm_vblank_crtc.hwmode,
|
||||
* drm_crtc_vblank_helper_get_vblank_timestamp() used
|
||||
* &drm_vblank_crtc.hwmode,
|
||||
* which is filled out by calling drm_calc_timestamping_constants().
|
||||
*/
|
||||
struct drm_display_mode hwmode;
|
||||
|
@ -459,8 +459,8 @@ struct drm_crtc_helper_funcs {
|
||||
* Returns the current display scanout position from a CRTC and an
|
||||
* optional accurate ktime_get() timestamp of when the position was
|
||||
* measured. Note that this is a helper callback which is only used
|
||||
* if a driver uses drm_calc_vbltimestamp_from_scanoutpos() for the
|
||||
* @drm_driver.get_vblank_timestamp callback.
|
||||
* if a driver uses drm_crtc_vblank_helper_get_vblank_timestamp()
|
||||
* for the @drm_crtc_funcs.get_vblank_timestamp callback.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
|
@ -174,13 +174,13 @@ struct drm_vblank_crtc {
|
||||
unsigned int pipe;
|
||||
/**
|
||||
* @framedur_ns: Frame/Field duration in ns, used by
|
||||
* drm_calc_vbltimestamp_from_scanoutpos() and computed by
|
||||
* drm_crtc_vblank_helper_get_vblank_timestamp() and computed by
|
||||
* drm_calc_timestamping_constants().
|
||||
*/
|
||||
int framedur_ns;
|
||||
/**
|
||||
* @linedur_ns: Line duration in ns, used by
|
||||
* drm_calc_vbltimestamp_from_scanoutpos() and computed by
|
||||
* drm_crtc_vblank_helper_get_vblank_timestamp() and computed by
|
||||
* drm_calc_timestamping_constants().
|
||||
*/
|
||||
int linedur_ns;
|
||||
@ -190,8 +190,8 @@ struct drm_vblank_crtc {
|
||||
*
|
||||
* 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,
|
||||
* drm_crtc_vblank_helper_get_vblank_timestamp(). 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;
|
||||
@ -240,6 +240,10 @@ wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc);
|
||||
void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
|
||||
u32 max_vblank_count);
|
||||
|
||||
/*
|
||||
* Helpers for struct drm_crtc_funcs
|
||||
*/
|
||||
|
||||
typedef bool (*drm_vblank_get_scanout_position_func)(struct drm_crtc *crtc,
|
||||
bool in_vblank_irq,
|
||||
int *vpos, int *hpos,
|
||||
@ -263,5 +267,9 @@ drm_crtc_vblank_helper_get_vblank_timestamp_internal(struct drm_crtc *crtc,
|
||||
bool in_vblank_irq,
|
||||
drm_vblank_get_scanout_position_func get_scanout_position,
|
||||
drm_vblank_get_scanout_position_legacy_func get_scanout_position_legacy);
|
||||
bool drm_crtc_vblank_helper_get_vblank_timestamp(struct drm_crtc *crtc,
|
||||
int *max_error,
|
||||
ktime_t *vblank_time,
|
||||
bool in_vblank_irq);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user