linux_dsm_epyc7002/include/drm/drm_vblank.h
Thomas Zimmermann 7beb691f1e drm: Initialize struct drm_crtc_state.no_vblank from device settings
At the end of a commit, atomic helpers can generate a fake VBLANK event
automatically. Originally implemented for writeback connectors, the
functionality can be used by any driver and/or hardware without proper
VBLANK interrupt.

The patch updates the documentation to make this behaviour official:
settings struct drm_crtc_state.no_vblank to true enables automatic
generation of fake VBLANK events.

The new interface drm_dev_has_vblank() returns true if vblanking has
been initialized for a device, or false otherwise. Atomic helpers use
this function when initializing no_vblank in the CRTC state in
drm_atomic_helper_check_modeset(). If vblanking has been initialized
for a device, no_blank is disabled. Otherwise it's enabled. Hence,
atomic helpers will automatically send out fake VBLANK events with any
driver that did not initialize vblanking.

v5:
	* more precise documentation and commit message
v4:
	* replace drm_crtc_has_vblank() with drm_dev_has_vblank()
	* add drm_dev_has_vblank() in this patch
	* move driver changes into separate patches
v3:
	* squash all related changes patches into this patch

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/20200129120531.6891-2-tzimmermann@suse.de
2020-01-30 08:57:12 +01:00

243 lines
8.1 KiB
C

/*
* Copyright 2016 Intel Corp.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _DRM_VBLANK_H_
#define _DRM_VBLANK_H_
#include <linux/seqlock.h>
#include <linux/idr.h>
#include <linux/poll.h>
#include <drm/drm_file.h>
#include <drm/drm_modes.h>
struct drm_device;
struct drm_crtc;
/**
* struct drm_pending_vblank_event - pending vblank event tracking
*/
struct drm_pending_vblank_event {
/**
* @base: Base structure for tracking pending DRM events.
*/
struct drm_pending_event base;
/**
* @pipe: drm_crtc_index() of the &drm_crtc this event is for.
*/
unsigned int pipe;
/**
* @sequence: frame event should be triggered at
*/
u64 sequence;
/**
* @event: Actual event which will be sent to userspace.
*/
union {
/**
* @event.base: DRM event base class.
*/
struct drm_event base;
/**
* @event.vbl:
*
* Event payload for vblank events, requested through
* either the MODE_PAGE_FLIP or MODE_ATOMIC IOCTL. Also
* generated by the legacy WAIT_VBLANK IOCTL, but new userspace
* should use MODE_QUEUE_SEQUENCE and &event.seq instead.
*/
struct drm_event_vblank vbl;
/**
* @event.seq: Event payload for the MODE_QUEUEU_SEQUENCE IOCTL.
*/
struct drm_event_crtc_sequence seq;
} event;
};
/**
* struct drm_vblank_crtc - vblank tracking for a CRTC
*
* This structure tracks the vblank state for one CRTC.
*
* Note that for historical reasons - the vblank handling code is still shared
* with legacy/non-kms drivers - this is a free-standing structure not directly
* connected to &struct drm_crtc. But all public interface functions are taking
* a &struct drm_crtc to hide this implementation detail.
*/
struct drm_vblank_crtc {
/**
* @dev: Pointer to the &drm_device.
*/
struct drm_device *dev;
/**
* @queue: Wait queue for vblank waiters.
*/
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
* &drm_device.max_vblank_count value.
*/
struct timer_list disable_timer;
/**
* @seqlock: Protect vblank count and time.
*/
seqlock_t seqlock;
/**
* @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.
*/
atomic64_t count;
/**
* @time: Vblank timestamp corresponding to @count.
*/
ktime_t time;
/**
* @refcount: Number of users/waiters of the vblank interrupt. Only when
* this refcount reaches 0 can the hardware interrupt be disabled using
* @disable_timer.
*/
atomic_t refcount;
/**
* @last: Protected by &drm_device.vbl_lock, used for wraparound handling.
*/
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
* hardware counter resetting/jumping. KMS drivers should instead just
* call drm_crtc_vblank_off() and drm_crtc_vblank_on(), which explicitly
* save and restore the vblank count.
*/
unsigned int inmodeset;
/**
* @pipe: drm_crtc_index() of the &drm_crtc corresponding to this
* structure.
*/
unsigned int pipe;
/**
* @framedur_ns: Frame/Field duration in ns, used by
* drm_calc_vbltimestamp_from_scanoutpos() 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_calc_timestamping_constants().
*/
int linedur_ns;
/**
* @hwmode:
*
* 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,
* because that one is really hard to get from interrupt context.
*/
struct drm_display_mode hwmode;
/**
* @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;
};
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);
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,
struct drm_pending_vblank_event *e);
void drm_vblank_set_event(struct drm_pending_vblank_event *e,
u64 *seq,
ktime_t *now);
bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe);
bool drm_crtc_handle_vblank(struct drm_crtc *crtc);
int drm_crtc_vblank_get(struct drm_crtc *crtc);
void drm_crtc_vblank_put(struct drm_crtc *crtc);
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(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);
#endif