aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMario Kleiner <mario.kleiner@tuebingen.mpg.de>2010-12-07 22:07:19 -0500
committerChris Wilson <chris@chris-wilson.co.uk>2010-12-16 16:02:24 -0500
commit0af7e4dff50454905092d468e91c1ef92e10e6b4 (patch)
tree6c1c9542720c6cf3b6de7a9ac6e8216ba55aebbc
parentd8c58fabd75021cdd99abcd96513cb088d41092b (diff)
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>
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c2
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h7
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c86
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h1
-rw-r--r--drivers/gpu/drm/i915/intel_display.c29
5 files changed, 119 insertions, 6 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index bdb29b2a01ed..9eee6cf7901e 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -652,6 +652,8 @@ static struct drm_driver driver = {
652 .device_is_agp = i915_driver_device_is_agp, 652 .device_is_agp = i915_driver_device_is_agp,
653 .enable_vblank = i915_enable_vblank, 653 .enable_vblank = i915_enable_vblank,
654 .disable_vblank = i915_disable_vblank, 654 .disable_vblank = i915_disable_vblank,
655 .get_vblank_timestamp = i915_get_vblank_timestamp,
656 .get_scanout_position = i915_get_crtc_scanoutpos,
655 .irq_preinstall = i915_driver_irq_preinstall, 657 .irq_preinstall = i915_driver_irq_preinstall,
656 .irq_postinstall = i915_driver_irq_postinstall, 658 .irq_postinstall = i915_driver_irq_postinstall,
657 .irq_uninstall = i915_driver_irq_uninstall, 659 .irq_uninstall = i915_driver_irq_uninstall,
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 30780f2cab6f..53dfc8398a96 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1019,6 +1019,13 @@ void
1019i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask); 1019i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
1020 1020
1021void intel_enable_asle (struct drm_device *dev); 1021void intel_enable_asle (struct drm_device *dev);
1022int i915_get_vblank_timestamp(struct drm_device *dev, int crtc,
1023 int *max_error,
1024 struct timeval *vblank_time,
1025 unsigned flags);
1026
1027int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
1028 int *vpos, int *hpos);
1022 1029
1023#ifdef CONFIG_DEBUG_FS 1030#ifdef CONFIG_DEBUG_FS
1024extern void i915_destroy_error_state(struct drm_device *dev); 1031extern void i915_destroy_error_state(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index e4a2e2c3dbe3..adf983f01dda 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -248,6 +248,92 @@ u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
248 return I915_READ(reg); 248 return I915_READ(reg);
249} 249}
250 250
251int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
252 int *vpos, int *hpos)
253{
254 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
255 u32 vbl = 0, position = 0;
256 int vbl_start, vbl_end, htotal, vtotal;
257 bool in_vbl = true;
258 int ret = 0;
259
260 if (!i915_pipe_enabled(dev, pipe)) {
261 DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled "
262 "pipe %d\n", pipe);
263 return 0;
264 }
265
266 /* Get vtotal. */
267 vtotal = 1 + ((I915_READ(VTOTAL(pipe)) >> 16) & 0x1fff);
268
269 if (INTEL_INFO(dev)->gen >= 4) {
270 /* No obvious pixelcount register. Only query vertical
271 * scanout position from Display scan line register.
272 */
273 position = I915_READ(PIPEDSL(pipe));
274
275 /* Decode into vertical scanout position. Don't have
276 * horizontal scanout position.
277 */
278 *vpos = position & 0x1fff;
279 *hpos = 0;
280 } else {
281 /* Have access to pixelcount since start of frame.
282 * We can split this into vertical and horizontal
283 * scanout position.
284 */
285 position = (I915_READ(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
286
287 htotal = 1 + ((I915_READ(HTOTAL(pipe)) >> 16) & 0x1fff);
288 *vpos = position / htotal;
289 *hpos = position - (*vpos * htotal);
290 }
291
292 /* Query vblank area. */
293 vbl = I915_READ(VBLANK(pipe));
294
295 /* Test position against vblank region. */
296 vbl_start = vbl & 0x1fff;
297 vbl_end = (vbl >> 16) & 0x1fff;
298
299 if ((*vpos < vbl_start) || (*vpos > vbl_end))
300 in_vbl = false;
301
302 /* Inside "upper part" of vblank area? Apply corrective offset: */
303 if (in_vbl && (*vpos >= vbl_start))
304 *vpos = *vpos - vtotal;
305
306 /* Readouts valid? */
307 if (vbl > 0)
308 ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
309
310 /* In vblank? */
311 if (in_vbl)
312 ret |= DRM_SCANOUTPOS_INVBL;
313
314 return ret;
315}
316
317int i915_get_vblank_timestamp(struct drm_device *dev, int crtc,
318 int *max_error,
319 struct timeval *vblank_time,
320 unsigned flags)
321{
322 struct drm_crtc *drmcrtc;
323
324 if (crtc < 0 || crtc >= dev->num_crtcs) {
325 DRM_ERROR("Invalid crtc %d\n", crtc);
326 return -EINVAL;
327 }
328
329 /* Get drm_crtc to timestamp: */
330 drmcrtc = intel_get_crtc_for_pipe(dev, crtc);
331
332 /* Helper routine in DRM core does all the work: */
333 return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
334 vblank_time, flags, drmcrtc);
335}
336
251/* 337/*
252 * Handle hotplug events outside the interrupt handler proper. 338 * Handle hotplug events outside the interrupt handler proper.
253 */ 339 */
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 820e9dfaadc7..c2231f7d2d97 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -2253,6 +2253,7 @@
2253#define PIPESRC(pipe) _PIPE(pipe, PIPEASRC, PIPEBSRC) 2253#define PIPESRC(pipe) _PIPE(pipe, PIPEASRC, PIPEBSRC)
2254#define PIPECONF(pipe) _PIPE(pipe, PIPEACONF, PIPEBCONF) 2254#define PIPECONF(pipe) _PIPE(pipe, PIPEACONF, PIPEBCONF)
2255#define PIPEDSL(pipe) _PIPE(pipe, PIPEADSL, PIPEBDSL) 2255#define PIPEDSL(pipe) _PIPE(pipe, PIPEADSL, PIPEBDSL)
2256#define PIPEFRAMEPIXEL(pipe) _PIPE(pipe, PIPEAFRAMEPIXEL, PIPEBFRAMEPIXEL)
2256 2257
2257#define DSPARB 0x70030 2258#define DSPARB 0x70030
2258#define DSPARB_CSTART_MASK (0x7f << 7) 2259#define DSPARB_CSTART_MASK (0x7f << 7)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 8645a974a499..0c201d684584 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -5252,7 +5252,8 @@ static void intel_unpin_work_fn(struct work_struct *__work)
5252} 5252}
5253 5253
5254static void do_intel_finish_page_flip(struct drm_device *dev, 5254static void do_intel_finish_page_flip(struct drm_device *dev,
5255 struct drm_crtc *crtc) 5255 struct drm_crtc *crtc,
5256 int called_before_vblirq)
5256{ 5257{
5257 drm_i915_private_t *dev_priv = dev->dev_private; 5258 drm_i915_private_t *dev_priv = dev->dev_private;
5258 struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 5259 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -5274,19 +5275,33 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
5274 } 5275 }
5275 5276
5276 intel_crtc->unpin_work = NULL; 5277 intel_crtc->unpin_work = NULL;
5277 drm_vblank_put(dev, intel_crtc->pipe);
5278 5278
5279 if (work->event) { 5279 if (work->event) {
5280 e = work->event; 5280 e = work->event;
5281 do_gettimeofday(&now); 5281 e->event.sequence = drm_vblank_count_and_time(dev, intel_crtc->pipe, &now);
5282 e->event.sequence = drm_vblank_count(dev, intel_crtc->pipe); 5282
5283 /* Called before vblank count and timestamps have
5284 * been updated for the vblank interval of flip
5285 * completion? Need to increment vblank count and
5286 * add one videorefresh duration to returned timestamp
5287 * to account for this.
5288 */
5289 if (called_before_vblirq) {
5290 e->event.sequence++;
5291 now = ns_to_timeval(timeval_to_ns(&now) +
5292 crtc->framedur_ns);
5293 }
5294
5283 e->event.tv_sec = now.tv_sec; 5295 e->event.tv_sec = now.tv_sec;
5284 e->event.tv_usec = now.tv_usec; 5296 e->event.tv_usec = now.tv_usec;
5297
5285 list_add_tail(&e->base.link, 5298 list_add_tail(&e->base.link,
5286 &e->base.file_priv->event_list); 5299 &e->base.file_priv->event_list);
5287 wake_up_interruptible(&e->base.file_priv->event_wait); 5300 wake_up_interruptible(&e->base.file_priv->event_wait);
5288 } 5301 }
5289 5302
5303 drm_vblank_put(dev, intel_crtc->pipe);
5304
5290 spin_unlock_irqrestore(&dev->event_lock, flags); 5305 spin_unlock_irqrestore(&dev->event_lock, flags);
5291 5306
5292 obj = work->old_fb_obj; 5307 obj = work->old_fb_obj;
@@ -5306,7 +5321,8 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe)
5306 drm_i915_private_t *dev_priv = dev->dev_private; 5321 drm_i915_private_t *dev_priv = dev->dev_private;
5307 struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; 5322 struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
5308 5323
5309 do_intel_finish_page_flip(dev, crtc); 5324 /* Called after drm_handle_vblank has run for finish vblank. */
5325 do_intel_finish_page_flip(dev, crtc, 0);
5310} 5326}
5311 5327
5312void intel_finish_page_flip_plane(struct drm_device *dev, int plane) 5328void 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)
5314 drm_i915_private_t *dev_priv = dev->dev_private; 5330 drm_i915_private_t *dev_priv = dev->dev_private;
5315 struct drm_crtc *crtc = dev_priv->plane_to_crtc_mapping[plane]; 5331 struct drm_crtc *crtc = dev_priv->plane_to_crtc_mapping[plane];
5316 5332
5317 do_intel_finish_page_flip(dev, crtc); 5333 /* Called before drm_handle_vblank has run for finish vblank. */
5334 do_intel_finish_page_flip(dev, crtc, 1);
5318} 5335}
5319 5336
5320void intel_prepare_page_flip(struct drm_device *dev, int plane) 5337void intel_prepare_page_flip(struct drm_device *dev, int plane)