diff options
Diffstat (limited to 'include/drm/drm_vblank.h')
| -rw-r--r-- | include/drm/drm_vblank.h | 166 |
1 files changed, 152 insertions, 14 deletions
diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h index 6ad9630d4f48..ffa564d79638 100644 --- a/include/drm/drm_vblank.h +++ b/include/drm/drm_vblank.h @@ -25,15 +25,17 @@ #define _DRM_VBLANK_H_ #include <linux/seqlock.h> +#include <linux/hrtimer.h> #include <linux/idr.h> #include <linux/poll.h> +#include <linux/kthread.h> #include <drm/drm_file.h> #include <drm/drm_modes.h> -#include <uapi/drm/drm.h> struct drm_device; struct drm_crtc; +struct drm_vblank_work; /** * struct drm_pending_vblank_event - pending vblank event tracking @@ -78,6 +80,53 @@ struct drm_pending_vblank_event { }; /** + * struct drm_vblank_crtc_config - vblank configuration for a CRTC + */ +struct drm_vblank_crtc_config { + /** + * @offdelay_ms: Vblank off delay in ms, used to determine how long + * &drm_vblank_crtc.disable_timer waits before disabling. + * + * Defaults to the value of drm_vblank_offdelay in drm_crtc_vblank_on(). + */ + int offdelay_ms; + + /** + * @disable_immediate: See &drm_device.vblank_disable_immediate + * for the exact semantics of immediate vblank disabling. + * + * Additionally, this tracks the disable immediate value per crtc, just + * in case it needs to differ from the default value for a given device. + * + * Defaults to the value of &drm_device.vblank_disable_immediate in + * drm_crtc_vblank_on(). + */ + bool disable_immediate; +}; + +/** + * struct drm_vblank_crtc_timer - vblank timer for a CRTC + */ +struct drm_vblank_crtc_timer { + /** + * @timer: The vblank's high-resolution timer + */ + struct hrtimer timer; + /** + * @interval_lock: Protects @interval + */ + spinlock_t interval_lock; + /** + * @interval: Duration between two vblanks + */ + ktime_t interval; + /** + * @crtc: The timer's CRTC + */ + struct drm_crtc *crtc; +}; + +/** * struct drm_vblank_crtc - vblank tracking for a CRTC * * This structure tracks the vblank state for one CRTC. @@ -98,8 +147,8 @@ struct drm_vblank_crtc { wait_queue_head_t queue; /** * @disable_timer: Disable timer for the delayed vblank disabling - * hysteresis logic. Vblank disabling is controlled through the - * drm_vblank_offdelay module option and the setting of the + * hysteresis logic. Vblank disabling is controlled through + * &drm_vblank_crtc_config.offdelay_ms and the setting of the * &drm_device.max_vblank_count value. */ struct timer_list disable_timer; @@ -110,9 +159,20 @@ struct drm_vblank_crtc { seqlock_t seqlock; /** - * @count: Current software vblank counter. + * @count: + * + * Current software vblank counter. + * + * Note that for a given vblank counter value drm_crtc_handle_vblank() + * and drm_crtc_vblank_count() or drm_crtc_vblank_count_and_time() + * provide a barrier: Any writes done before calling + * drm_crtc_handle_vblank() will be visible to callers of the later + * functions, iff the vblank count is the same or a later one. + * + * IMPORTANT: This guarantee requires barriers, therefor never access + * this field directly. Use drm_crtc_vblank_count() instead. */ - u64 count; + atomic64_t count; /** * @time: Vblank timestamp corresponding to @count. */ @@ -129,6 +189,26 @@ struct drm_vblank_crtc { */ u32 last; /** + * @max_vblank_count: + * + * Maximum value of the vblank registers for this crtc. This value +1 + * will result in a wrap-around of the vblank register. It is used + * by the vblank core to handle wrap-arounds. + * + * If set to zero the vblank core will try to guess the elapsed vblanks + * between times when the vblank interrupt is disabled through + * high-precision timestamps. That approach is suffering from small + * races and imprecision over longer time periods, hence exposing a + * hardware vblank counter is always recommended. + * + * This is the runtime configurable per-crtc maximum set through + * drm_crtc_set_max_vblank_count(). If this is used the driver + * must leave the device wide &drm_device.max_vblank_count at zero. + * + * If non-zero, &drm_crtc_funcs.get_vblank_counter must be set. + */ + u32 max_vblank_count; + /** * @inmodeset: Tracks whether the vblank is disabled due to a modeset. * For legacy driver bit 2 additionally tracks whether an additional * temporary vblank reference has been acquired to paper over the @@ -144,13 +224,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; @@ -160,25 +240,57 @@ 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; /** + * @config: Stores vblank configuration values for a given CRTC. + * Also, see drm_crtc_vblank_on_config(). + */ + struct drm_vblank_crtc_config config; + + /** * @enabled: Tracks the enabling state of the corresponding &drm_crtc to * avoid double-disabling and hence corrupting saved state. Needed by * drivers not using atomic KMS, since those might go through their CRTC * disabling functions multiple times. */ bool enabled; + + /** + * @worker: The &kthread_worker used for executing vblank works. + */ + struct kthread_worker *worker; + + /** + * @pending_work: A list of scheduled &drm_vblank_work items that are + * waiting for a future vblank. + */ + struct list_head pending_work; + + /** + * @work_wait_queue: The wait queue used for signaling that a + * &drm_vblank_work item has either finished executing, or was + * cancelled. + */ + wait_queue_head_t work_wait_queue; + + /** + * @vblank_timer: Holds the state of the vblank timer + */ + struct drm_vblank_crtc_timer vblank_timer; }; +struct drm_vblank_crtc *drm_crtc_vblank_crtc(struct drm_crtc *crtc); int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs); +bool drm_dev_has_vblank(const struct drm_device *dev); u64 drm_crtc_vblank_count(struct drm_crtc *crtc); u64 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc, ktime_t *vblanktime); +int drm_crtc_next_vblank_start(struct drm_crtc *crtc, ktime_t *vblanktime); void drm_crtc_send_vblank_event(struct drm_crtc *crtc, struct drm_pending_vblank_event *e); void drm_crtc_arm_vblank_event(struct drm_crtc *crtc, @@ -194,16 +306,42 @@ void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe); void drm_crtc_wait_one_vblank(struct drm_crtc *crtc); void drm_crtc_vblank_off(struct drm_crtc *crtc); void drm_crtc_vblank_reset(struct drm_crtc *crtc); +void drm_crtc_vblank_on_config(struct drm_crtc *crtc, + const struct drm_vblank_crtc_config *config); void drm_crtc_vblank_on(struct drm_crtc *crtc); u64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc); -void drm_vblank_restore(struct drm_device *dev, unsigned int pipe); void drm_crtc_vblank_restore(struct drm_crtc *crtc); -bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, - unsigned int pipe, int *max_error, - ktime_t *vblank_time, - bool in_vblank_irq); void drm_calc_timestamping_constants(struct drm_crtc *crtc, const struct drm_display_mode *mode); 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); + +int drm_crtc_vblank_start_timer(struct drm_crtc *crtc); +void drm_crtc_vblank_cancel_timer(struct drm_crtc *crtc); +void drm_crtc_vblank_get_vblank_timeout(struct drm_crtc *crtc, ktime_t *vblank_time); + +/* + * 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, + ktime_t *stime, + ktime_t *etime, + const struct drm_display_mode *mode); + +bool +drm_crtc_vblank_helper_get_vblank_timestamp_internal(struct drm_crtc *crtc, + int *max_error, + ktime_t *vblank_time, + bool in_vblank_irq, + drm_vblank_get_scanout_position_func get_scanout_position); +bool drm_crtc_vblank_helper_get_vblank_timestamp(struct drm_crtc *crtc, + int *max_error, + ktime_t *vblank_time, + bool in_vblank_irq); + #endif |
