mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 04:20:53 +07: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;
|
u64 vblank;
|
||||||
unsigned long flags;
|
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.");
|
"This function requires support for accurate vblank timestamps.");
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->vblank_time_lock, flags);
|
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
|
* Calculate and store various constants which are later needed by vblank and
|
||||||
* swap-completion timestamping, e.g, by
|
* swap-completion timestamping, e.g, by
|
||||||
* drm_calc_vbltimestamp_from_scanoutpos(). They are derived from CRTC's true
|
* drm_crtc_vblank_helper_get_vblank_timestamp(). They are derived from
|
||||||
* scanout timing, so they take things like panel scaling or other adjustments
|
* CRTC's true scanout timing, so they take things like panel scaling or
|
||||||
* into account.
|
* other adjustments into account.
|
||||||
*/
|
*/
|
||||||
void drm_calc_timestamping_constants(struct drm_crtc *crtc,
|
void drm_calc_timestamping_constants(struct drm_crtc *crtc,
|
||||||
const struct drm_display_mode *mode)
|
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
|
* Implements calculation of exact vblank timestamps from given drm_display_mode
|
||||||
* timings and current video scanout position of a CRTC. This can be directly
|
* 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
|
* used as the &drm_crtc_funcs.get_vblank_timestamp implementation of a kms
|
||||||
* if &drm_crtc_helper_funcs.get_scanout_position is implemented.
|
* 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
|
* The current implementation only handles standard video modes. For double scan
|
||||||
* and interlaced modes the driver is supposed to adjust the hardware mode
|
* 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);
|
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
|
* drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent
|
||||||
* vblank interval
|
* vblank interval
|
||||||
@ -827,15 +872,22 @@ static bool
|
|||||||
drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe,
|
drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe,
|
||||||
ktime_t *tvblank, bool in_vblank_irq)
|
ktime_t *tvblank, bool in_vblank_irq)
|
||||||
{
|
{
|
||||||
|
struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
/* Define requested maximum error on timestamps (nanoseconds). */
|
/* Define requested maximum error on timestamps (nanoseconds). */
|
||||||
int max_error = (int) drm_timestamp_precision * 1000;
|
int max_error = (int) drm_timestamp_precision * 1000;
|
||||||
|
|
||||||
/* Query driver if possible and precision timestamping enabled. */
|
/* 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,
|
ret = dev->driver->get_vblank_timestamp(dev, pipe, &max_error,
|
||||||
tvblank, in_vblank_irq);
|
tvblank, in_vblank_irq);
|
||||||
|
}
|
||||||
|
|
||||||
/* GPU high precision timestamp query unsupported or failed.
|
/* GPU high precision timestamp query unsupported or failed.
|
||||||
* Return current monotonic/gettimeofday timestamp as best estimate.
|
* Return current monotonic/gettimeofday timestamp as best estimate.
|
||||||
@ -1818,6 +1870,8 @@ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data,
|
|||||||
|
|
||||||
static void drm_handle_vblank_events(struct drm_device *dev, unsigned int pipe)
|
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;
|
struct drm_pending_vblank_event *e, *t;
|
||||||
ktime_t now;
|
ktime_t now;
|
||||||
u64 seq;
|
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);
|
send_vblank_event(dev, e, seq, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
trace_drm_vblank_event(pipe, seq, now,
|
if (crtc && crtc->funcs->get_vblank_timestamp)
|
||||||
dev->driver->get_vblank_timestamp != NULL);
|
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.
|
* new drivers as the replacement of &drm_driver.disable_vblank hook.
|
||||||
*/
|
*/
|
||||||
void (*disable_vblank)(struct drm_crtc *crtc);
|
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
|
* Programmed mode in hw, after adjustments for encoders, crtc, panel
|
||||||
* scaling etc. Should only be used by legacy drivers, for high
|
* scaling etc. Should only be used by legacy drivers, for high
|
||||||
* precision vblank timestamps in
|
* 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
|
* Note that atomic drivers should not use this, but instead use
|
||||||
* &drm_crtc_state.adjusted_mode. And for high-precision timestamps
|
* &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().
|
* which is filled out by calling drm_calc_timestamping_constants().
|
||||||
*/
|
*/
|
||||||
struct drm_display_mode hwmode;
|
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
|
* Returns the current display scanout position from a CRTC and an
|
||||||
* optional accurate ktime_get() timestamp of when the position was
|
* optional accurate ktime_get() timestamp of when the position was
|
||||||
* measured. Note that this is a helper callback which is only used
|
* measured. Note that this is a helper callback which is only used
|
||||||
* if a driver uses drm_calc_vbltimestamp_from_scanoutpos() for the
|
* if a driver uses drm_crtc_vblank_helper_get_vblank_timestamp()
|
||||||
* @drm_driver.get_vblank_timestamp callback.
|
* for the @drm_crtc_funcs.get_vblank_timestamp callback.
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
*
|
*
|
||||||
|
@ -174,13 +174,13 @@ struct drm_vblank_crtc {
|
|||||||
unsigned int pipe;
|
unsigned int pipe;
|
||||||
/**
|
/**
|
||||||
* @framedur_ns: Frame/Field duration in ns, used by
|
* @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().
|
* drm_calc_timestamping_constants().
|
||||||
*/
|
*/
|
||||||
int framedur_ns;
|
int framedur_ns;
|
||||||
/**
|
/**
|
||||||
* @linedur_ns: Line duration in ns, used by
|
* @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().
|
* drm_calc_timestamping_constants().
|
||||||
*/
|
*/
|
||||||
int linedur_ns;
|
int linedur_ns;
|
||||||
@ -190,8 +190,8 @@ struct drm_vblank_crtc {
|
|||||||
*
|
*
|
||||||
* Cache of the current hardware display mode. Only valid when @enabled
|
* Cache of the current hardware display mode. Only valid when @enabled
|
||||||
* is set. This is used by helpers like
|
* is set. This is used by helpers like
|
||||||
* drm_calc_vbltimestamp_from_scanoutpos(). We can't just access the
|
* drm_crtc_vblank_helper_get_vblank_timestamp(). We can't just access
|
||||||
* hardware mode by e.g. looking at &drm_crtc_state.adjusted_mode,
|
* the hardware mode by e.g. looking at &drm_crtc_state.adjusted_mode,
|
||||||
* because that one is really hard to get from interrupt context.
|
* because that one is really hard to get from interrupt context.
|
||||||
*/
|
*/
|
||||||
struct drm_display_mode hwmode;
|
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,
|
void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
|
||||||
u32 max_vblank_count);
|
u32 max_vblank_count);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helpers for struct drm_crtc_funcs
|
||||||
|
*/
|
||||||
|
|
||||||
typedef bool (*drm_vblank_get_scanout_position_func)(struct drm_crtc *crtc,
|
typedef bool (*drm_vblank_get_scanout_position_func)(struct drm_crtc *crtc,
|
||||||
bool in_vblank_irq,
|
bool in_vblank_irq,
|
||||||
int *vpos, int *hpos,
|
int *vpos, int *hpos,
|
||||||
@ -263,5 +267,9 @@ drm_crtc_vblank_helper_get_vblank_timestamp_internal(struct drm_crtc *crtc,
|
|||||||
bool in_vblank_irq,
|
bool in_vblank_irq,
|
||||||
drm_vblank_get_scanout_position_func get_scanout_position,
|
drm_vblank_get_scanout_position_func get_scanout_position,
|
||||||
drm_vblank_get_scanout_position_legacy_func get_scanout_position_legacy);
|
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
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user