Commit b2c077d0 authored by Rob Clark's avatar Rob Clark
Browse files

drm/vblank: Add helper to get next vblank time



Will be used in the next commit to set a deadline on fences that an
atomic update is waiting on.

v2: Calculate time at *start* of vblank period, not end
v3: Fix kbuild complaints

Signed-off-by: default avatarRob Clark <robdclark@chromium.org>
Reviewed-by: default avatarMario Kleiner <mario.kleiner.de@gmail.com>
parent f3823da7
Loading
Loading
Loading
Loading
+44 −9
Original line number Diff line number Diff line
@@ -844,10 +844,9 @@ bool drm_crtc_vblank_helper_get_vblank_timestamp(struct drm_crtc *crtc,
EXPORT_SYMBOL(drm_crtc_vblank_helper_get_vblank_timestamp);

/**
 * drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent
 *                             vblank interval
 * @dev: DRM device
 * @pipe: index of CRTC whose vblank timestamp to retrieve
 * drm_crtc_get_last_vbltimestamp - retrieve raw timestamp for the most
 *                                  recent vblank interval
 * @crtc: CRTC whose vblank timestamp to retrieve
 * @tvblank: Pointer to target time which should receive the timestamp
 * @in_vblank_irq:
 *     True when called from drm_crtc_handle_vblank().  Some drivers
@@ -865,10 +864,9 @@ EXPORT_SYMBOL(drm_crtc_vblank_helper_get_vblank_timestamp);
 * True if timestamp is considered to be very precise, false otherwise.
 */
static bool
drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe,
			  ktime_t *tvblank, bool in_vblank_irq)
drm_crtc_get_last_vbltimestamp(struct drm_crtc *crtc, 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). */
@@ -876,8 +874,6 @@ drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe,

	/* Query driver if possible and precision timestamping enabled. */
	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);
	}
@@ -891,6 +887,15 @@ drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe,
	return ret;
}

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);

	return drm_crtc_get_last_vbltimestamp(crtc, tvblank, in_vblank_irq);
}

/**
 * drm_crtc_vblank_count - retrieve "cooked" vblank counter value
 * @crtc: which counter to retrieve
@@ -980,6 +985,36 @@ u64 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc,
}
EXPORT_SYMBOL(drm_crtc_vblank_count_and_time);

/**
 * drm_crtc_next_vblank_start - calculate the time of the next vblank
 * @crtc: the crtc for which to calculate next vblank time
 * @vblanktime: pointer to time to receive the next vblank timestamp.
 *
 * Calculate the expected time of the start of the next vblank period,
 * based on time of previous vblank and frame duration
 */
int drm_crtc_next_vblank_start(struct drm_crtc *crtc, ktime_t *vblanktime)
{
	unsigned int pipe = drm_crtc_index(crtc);
	struct drm_vblank_crtc *vblank = &crtc->dev->vblank[pipe];
	struct drm_display_mode *mode = &vblank->hwmode;
	u64 vblank_start;

	if (!vblank->framedur_ns || !vblank->linedur_ns)
		return -EINVAL;

	if (!drm_crtc_get_last_vbltimestamp(crtc, vblanktime, false))
		return -EINVAL;

	vblank_start = DIV_ROUND_DOWN_ULL(
			(u64)vblank->framedur_ns * mode->crtc_vblank_start,
			mode->crtc_vtotal);
	*vblanktime  = ktime_add(*vblanktime, ns_to_ktime(vblank_start));

	return 0;
}
EXPORT_SYMBOL(drm_crtc_next_vblank_start);

static void send_vblank_event(struct drm_device *dev,
		struct drm_pending_vblank_event *e,
		u64 seq, ktime_t now)
+1 −0
Original line number Diff line number Diff line
@@ -230,6 +230,7 @@ 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,