mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-15 17:36:57 +07:00
drm/i915: Add support for precise vblank timestamping (v2)
v2: Change IS_IRONLAKE to IS_GEN5 to adapt to 2.6.37 This patch adds new functions for use by the drm core: .get_vblank_timestamp() provides a precise timestamp for the end of the most recent (or current) vblank interval of a given crtc, as needed for the DRI2 implementation of the OML_sync_control extension. It is a thin wrapper around the drm function drm_calc_vbltimestamp_from_scanoutpos() which does almost all the work. .get_scanout_position() provides the current horizontal and vertical video scanout position and "in vblank" status of a given crtc, as needed by the drm for use by drm_calc_vbltimestamp_from_scanoutpos(). The patch modifies the pageflip completion routine to use these precise vblank timestamps as the timestamps for pageflip completion events. This code has been only tested on a HP-Mini Netbook with Atom processor and Intel 945GME gpu. The codepath for (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev)) gpu's has not been tested so far due to lack of hardware. Signed-off-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de> Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
parent
d8c58fabd7
commit
0af7e4dff5
@ -652,6 +652,8 @@ static struct drm_driver driver = {
|
||||
.device_is_agp = i915_driver_device_is_agp,
|
||||
.enable_vblank = i915_enable_vblank,
|
||||
.disable_vblank = i915_disable_vblank,
|
||||
.get_vblank_timestamp = i915_get_vblank_timestamp,
|
||||
.get_scanout_position = i915_get_crtc_scanoutpos,
|
||||
.irq_preinstall = i915_driver_irq_preinstall,
|
||||
.irq_postinstall = i915_driver_irq_postinstall,
|
||||
.irq_uninstall = i915_driver_irq_uninstall,
|
||||
|
@ -1019,6 +1019,13 @@ void
|
||||
i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
|
||||
|
||||
void intel_enable_asle (struct drm_device *dev);
|
||||
int i915_get_vblank_timestamp(struct drm_device *dev, int crtc,
|
||||
int *max_error,
|
||||
struct timeval *vblank_time,
|
||||
unsigned flags);
|
||||
|
||||
int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
|
||||
int *vpos, int *hpos);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
extern void i915_destroy_error_state(struct drm_device *dev);
|
||||
|
@ -248,6 +248,92 @@ u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
|
||||
return I915_READ(reg);
|
||||
}
|
||||
|
||||
int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
|
||||
int *vpos, int *hpos)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
u32 vbl = 0, position = 0;
|
||||
int vbl_start, vbl_end, htotal, vtotal;
|
||||
bool in_vbl = true;
|
||||
int ret = 0;
|
||||
|
||||
if (!i915_pipe_enabled(dev, pipe)) {
|
||||
DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled "
|
||||
"pipe %d\n", pipe);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get vtotal. */
|
||||
vtotal = 1 + ((I915_READ(VTOTAL(pipe)) >> 16) & 0x1fff);
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
/* No obvious pixelcount register. Only query vertical
|
||||
* scanout position from Display scan line register.
|
||||
*/
|
||||
position = I915_READ(PIPEDSL(pipe));
|
||||
|
||||
/* Decode into vertical scanout position. Don't have
|
||||
* horizontal scanout position.
|
||||
*/
|
||||
*vpos = position & 0x1fff;
|
||||
*hpos = 0;
|
||||
} else {
|
||||
/* Have access to pixelcount since start of frame.
|
||||
* We can split this into vertical and horizontal
|
||||
* scanout position.
|
||||
*/
|
||||
position = (I915_READ(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
|
||||
|
||||
htotal = 1 + ((I915_READ(HTOTAL(pipe)) >> 16) & 0x1fff);
|
||||
*vpos = position / htotal;
|
||||
*hpos = position - (*vpos * htotal);
|
||||
}
|
||||
|
||||
/* Query vblank area. */
|
||||
vbl = I915_READ(VBLANK(pipe));
|
||||
|
||||
/* Test position against vblank region. */
|
||||
vbl_start = vbl & 0x1fff;
|
||||
vbl_end = (vbl >> 16) & 0x1fff;
|
||||
|
||||
if ((*vpos < vbl_start) || (*vpos > vbl_end))
|
||||
in_vbl = false;
|
||||
|
||||
/* Inside "upper part" of vblank area? Apply corrective offset: */
|
||||
if (in_vbl && (*vpos >= vbl_start))
|
||||
*vpos = *vpos - vtotal;
|
||||
|
||||
/* Readouts valid? */
|
||||
if (vbl > 0)
|
||||
ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
|
||||
|
||||
/* In vblank? */
|
||||
if (in_vbl)
|
||||
ret |= DRM_SCANOUTPOS_INVBL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int i915_get_vblank_timestamp(struct drm_device *dev, int crtc,
|
||||
int *max_error,
|
||||
struct timeval *vblank_time,
|
||||
unsigned flags)
|
||||
{
|
||||
struct drm_crtc *drmcrtc;
|
||||
|
||||
if (crtc < 0 || crtc >= dev->num_crtcs) {
|
||||
DRM_ERROR("Invalid crtc %d\n", crtc);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Get drm_crtc to timestamp: */
|
||||
drmcrtc = intel_get_crtc_for_pipe(dev, crtc);
|
||||
|
||||
/* Helper routine in DRM core does all the work: */
|
||||
return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
|
||||
vblank_time, flags, drmcrtc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle hotplug events outside the interrupt handler proper.
|
||||
*/
|
||||
|
@ -2253,6 +2253,7 @@
|
||||
#define PIPESRC(pipe) _PIPE(pipe, PIPEASRC, PIPEBSRC)
|
||||
#define PIPECONF(pipe) _PIPE(pipe, PIPEACONF, PIPEBCONF)
|
||||
#define PIPEDSL(pipe) _PIPE(pipe, PIPEADSL, PIPEBDSL)
|
||||
#define PIPEFRAMEPIXEL(pipe) _PIPE(pipe, PIPEAFRAMEPIXEL, PIPEBFRAMEPIXEL)
|
||||
|
||||
#define DSPARB 0x70030
|
||||
#define DSPARB_CSTART_MASK (0x7f << 7)
|
||||
|
@ -5252,7 +5252,8 @@ static void intel_unpin_work_fn(struct work_struct *__work)
|
||||
}
|
||||
|
||||
static void do_intel_finish_page_flip(struct drm_device *dev,
|
||||
struct drm_crtc *crtc)
|
||||
struct drm_crtc *crtc,
|
||||
int called_before_vblirq)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
@ -5274,19 +5275,33 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
|
||||
}
|
||||
|
||||
intel_crtc->unpin_work = NULL;
|
||||
drm_vblank_put(dev, intel_crtc->pipe);
|
||||
|
||||
if (work->event) {
|
||||
e = work->event;
|
||||
do_gettimeofday(&now);
|
||||
e->event.sequence = drm_vblank_count(dev, intel_crtc->pipe);
|
||||
e->event.sequence = drm_vblank_count_and_time(dev, intel_crtc->pipe, &now);
|
||||
|
||||
/* Called before vblank count and timestamps have
|
||||
* been updated for the vblank interval of flip
|
||||
* completion? Need to increment vblank count and
|
||||
* add one videorefresh duration to returned timestamp
|
||||
* to account for this.
|
||||
*/
|
||||
if (called_before_vblirq) {
|
||||
e->event.sequence++;
|
||||
now = ns_to_timeval(timeval_to_ns(&now) +
|
||||
crtc->framedur_ns);
|
||||
}
|
||||
|
||||
e->event.tv_sec = now.tv_sec;
|
||||
e->event.tv_usec = now.tv_usec;
|
||||
|
||||
list_add_tail(&e->base.link,
|
||||
&e->base.file_priv->event_list);
|
||||
wake_up_interruptible(&e->base.file_priv->event_wait);
|
||||
}
|
||||
|
||||
drm_vblank_put(dev, intel_crtc->pipe);
|
||||
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
|
||||
obj = work->old_fb_obj;
|
||||
@ -5306,7 +5321,8 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe)
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
|
||||
|
||||
do_intel_finish_page_flip(dev, crtc);
|
||||
/* Called after drm_handle_vblank has run for finish vblank. */
|
||||
do_intel_finish_page_flip(dev, crtc, 0);
|
||||
}
|
||||
|
||||
void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
|
||||
@ -5314,7 +5330,8 @@ void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_crtc *crtc = dev_priv->plane_to_crtc_mapping[plane];
|
||||
|
||||
do_intel_finish_page_flip(dev, crtc);
|
||||
/* Called before drm_handle_vblank has run for finish vblank. */
|
||||
do_intel_finish_page_flip(dev, crtc, 1);
|
||||
}
|
||||
|
||||
void intel_prepare_page_flip(struct drm_device *dev, int plane)
|
||||
|
Loading…
Reference in New Issue
Block a user