diff options
Diffstat (limited to 'drivers/gpu/drm/drm_vblank.c')
| -rw-r--r-- | drivers/gpu/drm/drm_vblank.c | 59 | 
1 files changed, 50 insertions, 9 deletions
diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index 2ff31717a3de..877e2067534f 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -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,42 @@ 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; +	struct drm_display_mode *mode; +	u64 vblank_start; + +	if (!drm_dev_has_vblank(crtc->dev)) +		return -EINVAL; + +	vblank = &crtc->dev->vblank[pipe]; +	mode = &vblank->hwmode; + +	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)  |