18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2016 Intel Corp.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the next
128c2ecf20Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
138c2ecf20Sopenharmony_ci * Software.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
168c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
188c2ecf20Sopenharmony_ci * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
198c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
208c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
218c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#ifndef _DRM_VBLANK_H_
258c2ecf20Sopenharmony_ci#define _DRM_VBLANK_H_
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include <linux/seqlock.h>
288c2ecf20Sopenharmony_ci#include <linux/idr.h>
298c2ecf20Sopenharmony_ci#include <linux/poll.h>
308c2ecf20Sopenharmony_ci#include <linux/kthread.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include <drm/drm_file.h>
338c2ecf20Sopenharmony_ci#include <drm/drm_modes.h>
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistruct drm_device;
368c2ecf20Sopenharmony_cistruct drm_crtc;
378c2ecf20Sopenharmony_cistruct drm_vblank_work;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/**
408c2ecf20Sopenharmony_ci * struct drm_pending_vblank_event - pending vblank event tracking
418c2ecf20Sopenharmony_ci */
428c2ecf20Sopenharmony_cistruct drm_pending_vblank_event {
438c2ecf20Sopenharmony_ci	/**
448c2ecf20Sopenharmony_ci	 * @base: Base structure for tracking pending DRM events.
458c2ecf20Sopenharmony_ci	 */
468c2ecf20Sopenharmony_ci	struct drm_pending_event base;
478c2ecf20Sopenharmony_ci	/**
488c2ecf20Sopenharmony_ci	 * @pipe: drm_crtc_index() of the &drm_crtc this event is for.
498c2ecf20Sopenharmony_ci	 */
508c2ecf20Sopenharmony_ci	unsigned int pipe;
518c2ecf20Sopenharmony_ci	/**
528c2ecf20Sopenharmony_ci	 * @sequence: frame event should be triggered at
538c2ecf20Sopenharmony_ci	 */
548c2ecf20Sopenharmony_ci	u64 sequence;
558c2ecf20Sopenharmony_ci	/**
568c2ecf20Sopenharmony_ci	 * @event: Actual event which will be sent to userspace.
578c2ecf20Sopenharmony_ci	 */
588c2ecf20Sopenharmony_ci	union {
598c2ecf20Sopenharmony_ci		/**
608c2ecf20Sopenharmony_ci		 * @event.base: DRM event base class.
618c2ecf20Sopenharmony_ci		 */
628c2ecf20Sopenharmony_ci		struct drm_event base;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci		/**
658c2ecf20Sopenharmony_ci		 * @event.vbl:
668c2ecf20Sopenharmony_ci		 *
678c2ecf20Sopenharmony_ci		 * Event payload for vblank events, requested through
688c2ecf20Sopenharmony_ci		 * either the MODE_PAGE_FLIP or MODE_ATOMIC IOCTL. Also
698c2ecf20Sopenharmony_ci		 * generated by the legacy WAIT_VBLANK IOCTL, but new userspace
708c2ecf20Sopenharmony_ci		 * should use MODE_QUEUE_SEQUENCE and &event.seq instead.
718c2ecf20Sopenharmony_ci		 */
728c2ecf20Sopenharmony_ci		struct drm_event_vblank vbl;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci		/**
758c2ecf20Sopenharmony_ci		 * @event.seq: Event payload for the MODE_QUEUEU_SEQUENCE IOCTL.
768c2ecf20Sopenharmony_ci		 */
778c2ecf20Sopenharmony_ci		struct drm_event_crtc_sequence seq;
788c2ecf20Sopenharmony_ci	} event;
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci/**
828c2ecf20Sopenharmony_ci * struct drm_vblank_crtc - vblank tracking for a CRTC
838c2ecf20Sopenharmony_ci *
848c2ecf20Sopenharmony_ci * This structure tracks the vblank state for one CRTC.
858c2ecf20Sopenharmony_ci *
868c2ecf20Sopenharmony_ci * Note that for historical reasons - the vblank handling code is still shared
878c2ecf20Sopenharmony_ci * with legacy/non-kms drivers - this is a free-standing structure not directly
888c2ecf20Sopenharmony_ci * connected to &struct drm_crtc. But all public interface functions are taking
898c2ecf20Sopenharmony_ci * a &struct drm_crtc to hide this implementation detail.
908c2ecf20Sopenharmony_ci */
918c2ecf20Sopenharmony_cistruct drm_vblank_crtc {
928c2ecf20Sopenharmony_ci	/**
938c2ecf20Sopenharmony_ci	 * @dev: Pointer to the &drm_device.
948c2ecf20Sopenharmony_ci	 */
958c2ecf20Sopenharmony_ci	struct drm_device *dev;
968c2ecf20Sopenharmony_ci	/**
978c2ecf20Sopenharmony_ci	 * @queue: Wait queue for vblank waiters.
988c2ecf20Sopenharmony_ci	 */
998c2ecf20Sopenharmony_ci	wait_queue_head_t queue;
1008c2ecf20Sopenharmony_ci	/**
1018c2ecf20Sopenharmony_ci	 * @disable_timer: Disable timer for the delayed vblank disabling
1028c2ecf20Sopenharmony_ci	 * hysteresis logic. Vblank disabling is controlled through the
1038c2ecf20Sopenharmony_ci	 * drm_vblank_offdelay module option and the setting of the
1048c2ecf20Sopenharmony_ci	 * &drm_device.max_vblank_count value.
1058c2ecf20Sopenharmony_ci	 */
1068c2ecf20Sopenharmony_ci	struct timer_list disable_timer;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	/**
1098c2ecf20Sopenharmony_ci	 * @seqlock: Protect vblank count and time.
1108c2ecf20Sopenharmony_ci	 */
1118c2ecf20Sopenharmony_ci	seqlock_t seqlock;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	/**
1148c2ecf20Sopenharmony_ci	 * @count:
1158c2ecf20Sopenharmony_ci	 *
1168c2ecf20Sopenharmony_ci	 * Current software vblank counter.
1178c2ecf20Sopenharmony_ci	 *
1188c2ecf20Sopenharmony_ci	 * Note that for a given vblank counter value drm_crtc_handle_vblank()
1198c2ecf20Sopenharmony_ci	 * and drm_crtc_vblank_count() or drm_crtc_vblank_count_and_time()
1208c2ecf20Sopenharmony_ci	 * provide a barrier: Any writes done before calling
1218c2ecf20Sopenharmony_ci	 * drm_crtc_handle_vblank() will be visible to callers of the later
1228c2ecf20Sopenharmony_ci	 * functions, iff the vblank count is the same or a later one.
1238c2ecf20Sopenharmony_ci	 *
1248c2ecf20Sopenharmony_ci	 * IMPORTANT: This guarantee requires barriers, therefor never access
1258c2ecf20Sopenharmony_ci	 * this field directly. Use drm_crtc_vblank_count() instead.
1268c2ecf20Sopenharmony_ci	 */
1278c2ecf20Sopenharmony_ci	atomic64_t count;
1288c2ecf20Sopenharmony_ci	/**
1298c2ecf20Sopenharmony_ci	 * @time: Vblank timestamp corresponding to @count.
1308c2ecf20Sopenharmony_ci	 */
1318c2ecf20Sopenharmony_ci	ktime_t time;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	/**
1348c2ecf20Sopenharmony_ci	 * @refcount: Number of users/waiters of the vblank interrupt. Only when
1358c2ecf20Sopenharmony_ci	 * this refcount reaches 0 can the hardware interrupt be disabled using
1368c2ecf20Sopenharmony_ci	 * @disable_timer.
1378c2ecf20Sopenharmony_ci	 */
1388c2ecf20Sopenharmony_ci	atomic_t refcount;
1398c2ecf20Sopenharmony_ci	/**
1408c2ecf20Sopenharmony_ci	 * @last: Protected by &drm_device.vbl_lock, used for wraparound handling.
1418c2ecf20Sopenharmony_ci	 */
1428c2ecf20Sopenharmony_ci	u32 last;
1438c2ecf20Sopenharmony_ci	/**
1448c2ecf20Sopenharmony_ci	 * @max_vblank_count:
1458c2ecf20Sopenharmony_ci	 *
1468c2ecf20Sopenharmony_ci	 * Maximum value of the vblank registers for this crtc. This value +1
1478c2ecf20Sopenharmony_ci	 * will result in a wrap-around of the vblank register. It is used
1488c2ecf20Sopenharmony_ci	 * by the vblank core to handle wrap-arounds.
1498c2ecf20Sopenharmony_ci	 *
1508c2ecf20Sopenharmony_ci	 * If set to zero the vblank core will try to guess the elapsed vblanks
1518c2ecf20Sopenharmony_ci	 * between times when the vblank interrupt is disabled through
1528c2ecf20Sopenharmony_ci	 * high-precision timestamps. That approach is suffering from small
1538c2ecf20Sopenharmony_ci	 * races and imprecision over longer time periods, hence exposing a
1548c2ecf20Sopenharmony_ci	 * hardware vblank counter is always recommended.
1558c2ecf20Sopenharmony_ci	 *
1568c2ecf20Sopenharmony_ci	 * This is the runtime configurable per-crtc maximum set through
1578c2ecf20Sopenharmony_ci	 * drm_crtc_set_max_vblank_count(). If this is used the driver
1588c2ecf20Sopenharmony_ci	 * must leave the device wide &drm_device.max_vblank_count at zero.
1598c2ecf20Sopenharmony_ci	 *
1608c2ecf20Sopenharmony_ci	 * If non-zero, &drm_crtc_funcs.get_vblank_counter must be set.
1618c2ecf20Sopenharmony_ci	 */
1628c2ecf20Sopenharmony_ci	u32 max_vblank_count;
1638c2ecf20Sopenharmony_ci	/**
1648c2ecf20Sopenharmony_ci	 * @inmodeset: Tracks whether the vblank is disabled due to a modeset.
1658c2ecf20Sopenharmony_ci	 * For legacy driver bit 2 additionally tracks whether an additional
1668c2ecf20Sopenharmony_ci	 * temporary vblank reference has been acquired to paper over the
1678c2ecf20Sopenharmony_ci	 * hardware counter resetting/jumping. KMS drivers should instead just
1688c2ecf20Sopenharmony_ci	 * call drm_crtc_vblank_off() and drm_crtc_vblank_on(), which explicitly
1698c2ecf20Sopenharmony_ci	 * save and restore the vblank count.
1708c2ecf20Sopenharmony_ci	 */
1718c2ecf20Sopenharmony_ci	unsigned int inmodeset;
1728c2ecf20Sopenharmony_ci	/**
1738c2ecf20Sopenharmony_ci	 * @pipe: drm_crtc_index() of the &drm_crtc corresponding to this
1748c2ecf20Sopenharmony_ci	 * structure.
1758c2ecf20Sopenharmony_ci	 */
1768c2ecf20Sopenharmony_ci	unsigned int pipe;
1778c2ecf20Sopenharmony_ci	/**
1788c2ecf20Sopenharmony_ci	 * @framedur_ns: Frame/Field duration in ns, used by
1798c2ecf20Sopenharmony_ci	 * drm_crtc_vblank_helper_get_vblank_timestamp() and computed by
1808c2ecf20Sopenharmony_ci	 * drm_calc_timestamping_constants().
1818c2ecf20Sopenharmony_ci	 */
1828c2ecf20Sopenharmony_ci	int framedur_ns;
1838c2ecf20Sopenharmony_ci	/**
1848c2ecf20Sopenharmony_ci	 * @linedur_ns: Line duration in ns, used by
1858c2ecf20Sopenharmony_ci	 * drm_crtc_vblank_helper_get_vblank_timestamp() and computed by
1868c2ecf20Sopenharmony_ci	 * drm_calc_timestamping_constants().
1878c2ecf20Sopenharmony_ci	 */
1888c2ecf20Sopenharmony_ci	int linedur_ns;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	/**
1918c2ecf20Sopenharmony_ci	 * @hwmode:
1928c2ecf20Sopenharmony_ci	 *
1938c2ecf20Sopenharmony_ci	 * Cache of the current hardware display mode. Only valid when @enabled
1948c2ecf20Sopenharmony_ci	 * is set. This is used by helpers like
1958c2ecf20Sopenharmony_ci	 * drm_crtc_vblank_helper_get_vblank_timestamp(). We can't just access
1968c2ecf20Sopenharmony_ci	 * the hardware mode by e.g. looking at &drm_crtc_state.adjusted_mode,
1978c2ecf20Sopenharmony_ci	 * because that one is really hard to get from interrupt context.
1988c2ecf20Sopenharmony_ci	 */
1998c2ecf20Sopenharmony_ci	struct drm_display_mode hwmode;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	/**
2028c2ecf20Sopenharmony_ci	 * @enabled: Tracks the enabling state of the corresponding &drm_crtc to
2038c2ecf20Sopenharmony_ci	 * avoid double-disabling and hence corrupting saved state. Needed by
2048c2ecf20Sopenharmony_ci	 * drivers not using atomic KMS, since those might go through their CRTC
2058c2ecf20Sopenharmony_ci	 * disabling functions multiple times.
2068c2ecf20Sopenharmony_ci	 */
2078c2ecf20Sopenharmony_ci	bool enabled;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	/**
2108c2ecf20Sopenharmony_ci	 * @worker: The &kthread_worker used for executing vblank works.
2118c2ecf20Sopenharmony_ci	 */
2128c2ecf20Sopenharmony_ci	struct kthread_worker *worker;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	/**
2158c2ecf20Sopenharmony_ci	 * @pending_work: A list of scheduled &drm_vblank_work items that are
2168c2ecf20Sopenharmony_ci	 * waiting for a future vblank.
2178c2ecf20Sopenharmony_ci	 */
2188c2ecf20Sopenharmony_ci	struct list_head pending_work;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	/**
2218c2ecf20Sopenharmony_ci	 * @work_wait_queue: The wait queue used for signaling that a
2228c2ecf20Sopenharmony_ci	 * &drm_vblank_work item has either finished executing, or was
2238c2ecf20Sopenharmony_ci	 * cancelled.
2248c2ecf20Sopenharmony_ci	 */
2258c2ecf20Sopenharmony_ci	wait_queue_head_t work_wait_queue;
2268c2ecf20Sopenharmony_ci};
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ciint drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs);
2298c2ecf20Sopenharmony_cibool drm_dev_has_vblank(const struct drm_device *dev);
2308c2ecf20Sopenharmony_ciu64 drm_crtc_vblank_count(struct drm_crtc *crtc);
2318c2ecf20Sopenharmony_ciu64 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc,
2328c2ecf20Sopenharmony_ci				   ktime_t *vblanktime);
2338c2ecf20Sopenharmony_civoid drm_crtc_send_vblank_event(struct drm_crtc *crtc,
2348c2ecf20Sopenharmony_ci			       struct drm_pending_vblank_event *e);
2358c2ecf20Sopenharmony_civoid drm_crtc_arm_vblank_event(struct drm_crtc *crtc,
2368c2ecf20Sopenharmony_ci			      struct drm_pending_vblank_event *e);
2378c2ecf20Sopenharmony_civoid drm_vblank_set_event(struct drm_pending_vblank_event *e,
2388c2ecf20Sopenharmony_ci			  u64 *seq,
2398c2ecf20Sopenharmony_ci			  ktime_t *now);
2408c2ecf20Sopenharmony_cibool drm_handle_vblank(struct drm_device *dev, unsigned int pipe);
2418c2ecf20Sopenharmony_cibool drm_crtc_handle_vblank(struct drm_crtc *crtc);
2428c2ecf20Sopenharmony_ciint drm_crtc_vblank_get(struct drm_crtc *crtc);
2438c2ecf20Sopenharmony_civoid drm_crtc_vblank_put(struct drm_crtc *crtc);
2448c2ecf20Sopenharmony_civoid drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe);
2458c2ecf20Sopenharmony_civoid drm_crtc_wait_one_vblank(struct drm_crtc *crtc);
2468c2ecf20Sopenharmony_civoid drm_crtc_vblank_off(struct drm_crtc *crtc);
2478c2ecf20Sopenharmony_civoid drm_crtc_vblank_reset(struct drm_crtc *crtc);
2488c2ecf20Sopenharmony_civoid drm_crtc_vblank_on(struct drm_crtc *crtc);
2498c2ecf20Sopenharmony_ciu64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc);
2508c2ecf20Sopenharmony_civoid drm_vblank_restore(struct drm_device *dev, unsigned int pipe);
2518c2ecf20Sopenharmony_civoid drm_crtc_vblank_restore(struct drm_crtc *crtc);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_civoid drm_calc_timestamping_constants(struct drm_crtc *crtc,
2548c2ecf20Sopenharmony_ci				     const struct drm_display_mode *mode);
2558c2ecf20Sopenharmony_ciwait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc);
2568c2ecf20Sopenharmony_civoid drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
2578c2ecf20Sopenharmony_ci				   u32 max_vblank_count);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci/*
2608c2ecf20Sopenharmony_ci * Helpers for struct drm_crtc_funcs
2618c2ecf20Sopenharmony_ci */
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_citypedef bool (*drm_vblank_get_scanout_position_func)(struct drm_crtc *crtc,
2648c2ecf20Sopenharmony_ci						     bool in_vblank_irq,
2658c2ecf20Sopenharmony_ci						     int *vpos, int *hpos,
2668c2ecf20Sopenharmony_ci						     ktime_t *stime,
2678c2ecf20Sopenharmony_ci						     ktime_t *etime,
2688c2ecf20Sopenharmony_ci						     const struct drm_display_mode *mode);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cibool
2718c2ecf20Sopenharmony_cidrm_crtc_vblank_helper_get_vblank_timestamp_internal(struct drm_crtc *crtc,
2728c2ecf20Sopenharmony_ci						     int *max_error,
2738c2ecf20Sopenharmony_ci						     ktime_t *vblank_time,
2748c2ecf20Sopenharmony_ci						     bool in_vblank_irq,
2758c2ecf20Sopenharmony_ci						     drm_vblank_get_scanout_position_func get_scanout_position);
2768c2ecf20Sopenharmony_cibool drm_crtc_vblank_helper_get_vblank_timestamp(struct drm_crtc *crtc,
2778c2ecf20Sopenharmony_ci						 int *max_error,
2788c2ecf20Sopenharmony_ci						 ktime_t *vblank_time,
2798c2ecf20Sopenharmony_ci						 bool in_vblank_irq);
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci#endif
282