diff options
-rw-r--r-- | drivers/gpu/drm/drm_crtc_helper.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_irq.c | 563 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_stub.c | 10 | ||||
-rw-r--r-- | include/drm/drmP.h | 93 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 9 |
5 files changed, 662 insertions, 26 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index f7af91cb273d..4c200931a6bc 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
@@ -336,7 +336,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, | |||
336 | struct drm_framebuffer *old_fb) | 336 | struct drm_framebuffer *old_fb) |
337 | { | 337 | { |
338 | struct drm_device *dev = crtc->dev; | 338 | struct drm_device *dev = crtc->dev; |
339 | struct drm_display_mode *adjusted_mode, saved_mode; | 339 | struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode; |
340 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | 340 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
341 | struct drm_encoder_helper_funcs *encoder_funcs; | 341 | struct drm_encoder_helper_funcs *encoder_funcs; |
342 | int saved_x, saved_y; | 342 | int saved_x, saved_y; |
@@ -350,6 +350,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, | |||
350 | if (!crtc->enabled) | 350 | if (!crtc->enabled) |
351 | return true; | 351 | return true; |
352 | 352 | ||
353 | saved_hwmode = crtc->hwmode; | ||
353 | saved_mode = crtc->mode; | 354 | saved_mode = crtc->mode; |
354 | saved_x = crtc->x; | 355 | saved_x = crtc->x; |
355 | saved_y = crtc->y; | 356 | saved_y = crtc->y; |
@@ -427,11 +428,21 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, | |||
427 | 428 | ||
428 | } | 429 | } |
429 | 430 | ||
431 | /* Store real post-adjustment hardware mode. */ | ||
432 | crtc->hwmode = *adjusted_mode; | ||
433 | |||
434 | /* Calculate and store various constants which | ||
435 | * are later needed by vblank and swap-completion | ||
436 | * timestamping. They are derived from true hwmode. | ||
437 | */ | ||
438 | drm_calc_timestamping_constants(crtc); | ||
439 | |||
430 | /* XXX free adjustedmode */ | 440 | /* XXX free adjustedmode */ |
431 | drm_mode_destroy(dev, adjusted_mode); | 441 | drm_mode_destroy(dev, adjusted_mode); |
432 | /* FIXME: add subpixel order */ | 442 | /* FIXME: add subpixel order */ |
433 | done: | 443 | done: |
434 | if (!ret) { | 444 | if (!ret) { |
445 | crtc->hwmode = saved_hwmode; | ||
435 | crtc->mode = saved_mode; | 446 | crtc->mode = saved_mode; |
436 | crtc->x = saved_x; | 447 | crtc->x = saved_x; |
437 | crtc->y = saved_y; | 448 | crtc->y = saved_y; |
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 9d3a5030b6e1..4e82d0d3c378 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c | |||
@@ -40,6 +40,22 @@ | |||
40 | #include <linux/slab.h> | 40 | #include <linux/slab.h> |
41 | 41 | ||
42 | #include <linux/vgaarb.h> | 42 | #include <linux/vgaarb.h> |
43 | |||
44 | /* Access macro for slots in vblank timestamp ringbuffer. */ | ||
45 | #define vblanktimestamp(dev, crtc, count) ( \ | ||
46 | (dev)->_vblank_time[(crtc) * DRM_VBLANKTIME_RBSIZE + \ | ||
47 | ((count) % DRM_VBLANKTIME_RBSIZE)]) | ||
48 | |||
49 | /* Retry timestamp calculation up to 3 times to satisfy | ||
50 | * drm_timestamp_precision before giving up. | ||
51 | */ | ||
52 | #define DRM_TIMESTAMP_MAXRETRIES 3 | ||
53 | |||
54 | /* Threshold in nanoseconds for detection of redundant | ||
55 | * vblank irq in drm_handle_vblank(). 1 msec should be ok. | ||
56 | */ | ||
57 | #define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000 | ||
58 | |||
43 | /** | 59 | /** |
44 | * Get interrupt from bus id. | 60 | * Get interrupt from bus id. |
45 | * | 61 | * |
@@ -77,6 +93,87 @@ int drm_irq_by_busid(struct drm_device *dev, void *data, | |||
77 | return 0; | 93 | return 0; |
78 | } | 94 | } |
79 | 95 | ||
96 | /* | ||
97 | * Clear vblank timestamp buffer for a crtc. | ||
98 | */ | ||
99 | static void clear_vblank_timestamps(struct drm_device *dev, int crtc) | ||
100 | { | ||
101 | memset(&dev->_vblank_time[crtc * DRM_VBLANKTIME_RBSIZE], 0, | ||
102 | DRM_VBLANKTIME_RBSIZE * sizeof(struct timeval)); | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * Disable vblank irq's on crtc, make sure that last vblank count | ||
107 | * of hardware and corresponding consistent software vblank counter | ||
108 | * are preserved, even if there are any spurious vblank irq's after | ||
109 | * disable. | ||
110 | */ | ||
111 | static void vblank_disable_and_save(struct drm_device *dev, int crtc) | ||
112 | { | ||
113 | unsigned long irqflags; | ||
114 | u32 vblcount; | ||
115 | s64 diff_ns; | ||
116 | int vblrc; | ||
117 | struct timeval tvblank; | ||
118 | |||
119 | /* Prevent vblank irq processing while disabling vblank irqs, | ||
120 | * so no updates of timestamps or count can happen after we've | ||
121 | * disabled. Needed to prevent races in case of delayed irq's. | ||
122 | * Disable preemption, so vblank_time_lock is held as short as | ||
123 | * possible, even under a kernel with PREEMPT_RT patches. | ||
124 | */ | ||
125 | preempt_disable(); | ||
126 | spin_lock_irqsave(&dev->vblank_time_lock, irqflags); | ||
127 | |||
128 | dev->driver->disable_vblank(dev, crtc); | ||
129 | dev->vblank_enabled[crtc] = 0; | ||
130 | |||
131 | /* No further vblank irq's will be processed after | ||
132 | * this point. Get current hardware vblank count and | ||
133 | * vblank timestamp, repeat until they are consistent. | ||
134 | * | ||
135 | * FIXME: There is still a race condition here and in | ||
136 | * drm_update_vblank_count() which can cause off-by-one | ||
137 | * reinitialization of software vblank counter. If gpu | ||
138 | * vblank counter doesn't increment exactly at the leading | ||
139 | * edge of a vblank interval, then we can lose 1 count if | ||
140 | * we happen to execute between start of vblank and the | ||
141 | * delayed gpu counter increment. | ||
142 | */ | ||
143 | do { | ||
144 | dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc); | ||
145 | vblrc = drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0); | ||
146 | } while (dev->last_vblank[crtc] != dev->driver->get_vblank_counter(dev, crtc)); | ||
147 | |||
148 | /* Compute time difference to stored timestamp of last vblank | ||
149 | * as updated by last invocation of drm_handle_vblank() in vblank irq. | ||
150 | */ | ||
151 | vblcount = atomic_read(&dev->_vblank_count[crtc]); | ||
152 | diff_ns = timeval_to_ns(&tvblank) - | ||
153 | timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount)); | ||
154 | |||
155 | /* If there is at least 1 msec difference between the last stored | ||
156 | * timestamp and tvblank, then we are currently executing our | ||
157 | * disable inside a new vblank interval, the tvblank timestamp | ||
158 | * corresponds to this new vblank interval and the irq handler | ||
159 | * for this vblank didn't run yet and won't run due to our disable. | ||
160 | * Therefore we need to do the job of drm_handle_vblank() and | ||
161 | * increment the vblank counter by one to account for this vblank. | ||
162 | * | ||
163 | * Skip this step if there isn't any high precision timestamp | ||
164 | * available. In that case we can't account for this and just | ||
165 | * hope for the best. | ||
166 | */ | ||
167 | if ((vblrc > 0) && (abs(diff_ns) > 1000000)) | ||
168 | atomic_inc(&dev->_vblank_count[crtc]); | ||
169 | |||
170 | /* Invalidate all timestamps while vblank irq's are off. */ | ||
171 | clear_vblank_timestamps(dev, crtc); | ||
172 | |||
173 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); | ||
174 | preempt_enable(); | ||
175 | } | ||
176 | |||
80 | static void vblank_disable_fn(unsigned long arg) | 177 | static void vblank_disable_fn(unsigned long arg) |
81 | { | 178 | { |
82 | struct drm_device *dev = (struct drm_device *)arg; | 179 | struct drm_device *dev = (struct drm_device *)arg; |
@@ -91,10 +188,7 @@ static void vblank_disable_fn(unsigned long arg) | |||
91 | if (atomic_read(&dev->vblank_refcount[i]) == 0 && | 188 | if (atomic_read(&dev->vblank_refcount[i]) == 0 && |
92 | dev->vblank_enabled[i]) { | 189 | dev->vblank_enabled[i]) { |
93 | DRM_DEBUG("disabling vblank on crtc %d\n", i); | 190 | DRM_DEBUG("disabling vblank on crtc %d\n", i); |
94 | dev->last_vblank[i] = | 191 | vblank_disable_and_save(dev, i); |
95 | dev->driver->get_vblank_counter(dev, i); | ||
96 | dev->driver->disable_vblank(dev, i); | ||
97 | dev->vblank_enabled[i] = 0; | ||
98 | } | 192 | } |
99 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | 193 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
100 | } | 194 | } |
@@ -117,6 +211,7 @@ void drm_vblank_cleanup(struct drm_device *dev) | |||
117 | kfree(dev->last_vblank); | 211 | kfree(dev->last_vblank); |
118 | kfree(dev->last_vblank_wait); | 212 | kfree(dev->last_vblank_wait); |
119 | kfree(dev->vblank_inmodeset); | 213 | kfree(dev->vblank_inmodeset); |
214 | kfree(dev->_vblank_time); | ||
120 | 215 | ||
121 | dev->num_crtcs = 0; | 216 | dev->num_crtcs = 0; |
122 | } | 217 | } |
@@ -129,6 +224,8 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) | |||
129 | setup_timer(&dev->vblank_disable_timer, vblank_disable_fn, | 224 | setup_timer(&dev->vblank_disable_timer, vblank_disable_fn, |
130 | (unsigned long)dev); | 225 | (unsigned long)dev); |
131 | spin_lock_init(&dev->vbl_lock); | 226 | spin_lock_init(&dev->vbl_lock); |
227 | spin_lock_init(&dev->vblank_time_lock); | ||
228 | |||
132 | dev->num_crtcs = num_crtcs; | 229 | dev->num_crtcs = num_crtcs; |
133 | 230 | ||
134 | dev->vbl_queue = kmalloc(sizeof(wait_queue_head_t) * num_crtcs, | 231 | dev->vbl_queue = kmalloc(sizeof(wait_queue_head_t) * num_crtcs, |
@@ -161,6 +258,19 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) | |||
161 | if (!dev->vblank_inmodeset) | 258 | if (!dev->vblank_inmodeset) |
162 | goto err; | 259 | goto err; |
163 | 260 | ||
261 | dev->_vblank_time = kcalloc(num_crtcs * DRM_VBLANKTIME_RBSIZE, | ||
262 | sizeof(struct timeval), GFP_KERNEL); | ||
263 | if (!dev->_vblank_time) | ||
264 | goto err; | ||
265 | |||
266 | DRM_INFO("Supports vblank timestamp caching Rev 1 (10.10.2010).\n"); | ||
267 | |||
268 | /* Driver specific high-precision vblank timestamping supported? */ | ||
269 | if (dev->driver->get_vblank_timestamp) | ||
270 | DRM_INFO("Driver supports precise vblank timestamp query.\n"); | ||
271 | else | ||
272 | DRM_INFO("No driver support for vblank timestamp query.\n"); | ||
273 | |||
164 | /* Zero per-crtc vblank stuff */ | 274 | /* Zero per-crtc vblank stuff */ |
165 | for (i = 0; i < num_crtcs; i++) { | 275 | for (i = 0; i < num_crtcs; i++) { |
166 | init_waitqueue_head(&dev->vbl_queue[i]); | 276 | init_waitqueue_head(&dev->vbl_queue[i]); |
@@ -279,7 +389,7 @@ EXPORT_SYMBOL(drm_irq_install); | |||
279 | * | 389 | * |
280 | * Calls the driver's \c drm_driver_irq_uninstall() function, and stops the irq. | 390 | * Calls the driver's \c drm_driver_irq_uninstall() function, and stops the irq. |
281 | */ | 391 | */ |
282 | int drm_irq_uninstall(struct drm_device * dev) | 392 | int drm_irq_uninstall(struct drm_device *dev) |
283 | { | 393 | { |
284 | unsigned long irqflags; | 394 | unsigned long irqflags; |
285 | int irq_enabled, i; | 395 | int irq_enabled, i; |
@@ -335,7 +445,9 @@ int drm_control(struct drm_device *dev, void *data, | |||
335 | { | 445 | { |
336 | struct drm_control *ctl = data; | 446 | struct drm_control *ctl = data; |
337 | 447 | ||
338 | /* if we haven't irq we fallback for compatibility reasons - this used to be a separate function in drm_dma.h */ | 448 | /* if we haven't irq we fallback for compatibility reasons - |
449 | * this used to be a separate function in drm_dma.h | ||
450 | */ | ||
339 | 451 | ||
340 | 452 | ||
341 | switch (ctl->func) { | 453 | switch (ctl->func) { |
@@ -360,6 +472,287 @@ int drm_control(struct drm_device *dev, void *data, | |||
360 | } | 472 | } |
361 | 473 | ||
362 | /** | 474 | /** |
475 | * drm_calc_timestamping_constants - Calculate and | ||
476 | * store various constants which are later needed by | ||
477 | * vblank and swap-completion timestamping, e.g, by | ||
478 | * drm_calc_vbltimestamp_from_scanoutpos(). | ||
479 | * They are derived from crtc's true scanout timing, | ||
480 | * so they take things like panel scaling or other | ||
481 | * adjustments into account. | ||
482 | * | ||
483 | * @crtc drm_crtc whose timestamp constants should be updated. | ||
484 | * | ||
485 | */ | ||
486 | void drm_calc_timestamping_constants(struct drm_crtc *crtc) | ||
487 | { | ||
488 | s64 linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0; | ||
489 | u64 dotclock; | ||
490 | |||
491 | /* Dot clock in Hz: */ | ||
492 | dotclock = (u64) crtc->hwmode.clock * 1000; | ||
493 | |||
494 | /* Valid dotclock? */ | ||
495 | if (dotclock > 0) { | ||
496 | /* Convert scanline length in pixels and video dot clock to | ||
497 | * line duration, frame duration and pixel duration in | ||
498 | * nanoseconds: | ||
499 | */ | ||
500 | pixeldur_ns = (s64) div64_u64(1000000000, dotclock); | ||
501 | linedur_ns = (s64) div64_u64(((u64) crtc->hwmode.crtc_htotal * | ||
502 | 1000000000), dotclock); | ||
503 | framedur_ns = (s64) crtc->hwmode.crtc_vtotal * linedur_ns; | ||
504 | } else | ||
505 | DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n", | ||
506 | crtc->base.id); | ||
507 | |||
508 | crtc->pixeldur_ns = pixeldur_ns; | ||
509 | crtc->linedur_ns = linedur_ns; | ||
510 | crtc->framedur_ns = framedur_ns; | ||
511 | |||
512 | DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n", | ||
513 | crtc->base.id, crtc->hwmode.crtc_htotal, | ||
514 | crtc->hwmode.crtc_vtotal, crtc->hwmode.crtc_vdisplay); | ||
515 | DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n", | ||
516 | crtc->base.id, (int) dotclock/1000, (int) framedur_ns, | ||
517 | (int) linedur_ns, (int) pixeldur_ns); | ||
518 | } | ||
519 | EXPORT_SYMBOL(drm_calc_timestamping_constants); | ||
520 | |||
521 | /** | ||
522 | * drm_calc_vbltimestamp_from_scanoutpos - helper routine for kms | ||
523 | * drivers. Implements calculation of exact vblank timestamps from | ||
524 | * given drm_display_mode timings and current video scanout position | ||
525 | * of a crtc. This can be called from within get_vblank_timestamp() | ||
526 | * implementation of a kms driver to implement the actual timestamping. | ||
527 | * | ||
528 | * Should return timestamps conforming to the OML_sync_control OpenML | ||
529 | * extension specification. The timestamp corresponds to the end of | ||
530 | * the vblank interval, aka start of scanout of topmost-leftmost display | ||
531 | * pixel in the following video frame. | ||
532 | * | ||
533 | * Requires support for optional dev->driver->get_scanout_position() | ||
534 | * in kms driver, plus a bit of setup code to provide a drm_display_mode | ||
535 | * that corresponds to the true scanout timing. | ||
536 | * | ||
537 | * The current implementation only handles standard video modes. It | ||
538 | * returns as no operation if a doublescan or interlaced video mode is | ||
539 | * active. Higher level code is expected to handle this. | ||
540 | * | ||
541 | * @dev: DRM device. | ||
542 | * @crtc: Which crtc's vblank timestamp to retrieve. | ||
543 | * @max_error: Desired maximum allowable error in timestamps (nanosecs). | ||
544 | * On return contains true maximum error of timestamp. | ||
545 | * @vblank_time: Pointer to struct timeval which should receive the timestamp. | ||
546 | * @flags: Flags to pass to driver: | ||
547 | * 0 = Default. | ||
548 | * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler. | ||
549 | * @refcrtc: drm_crtc* of crtc which defines scanout timing. | ||
550 | * | ||
551 | * Returns negative value on error, failure or if not supported in current | ||
552 | * video mode: | ||
553 | * | ||
554 | * -EINVAL - Invalid crtc. | ||
555 | * -EAGAIN - Temporary unavailable, e.g., called before initial modeset. | ||
556 | * -ENOTSUPP - Function not supported in current display mode. | ||
557 | * -EIO - Failed, e.g., due to failed scanout position query. | ||
558 | * | ||
559 | * Returns or'ed positive status flags on success: | ||
560 | * | ||
561 | * DRM_VBLANKTIME_SCANOUTPOS_METHOD - Signal this method used for timestamping. | ||
562 | * DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval. | ||
563 | * | ||
564 | */ | ||
565 | int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, | ||
566 | int *max_error, | ||
567 | struct timeval *vblank_time, | ||
568 | unsigned flags, | ||
569 | struct drm_crtc *refcrtc) | ||
570 | { | ||
571 | struct timeval stime, raw_time; | ||
572 | struct drm_display_mode *mode; | ||
573 | int vbl_status, vtotal, vdisplay; | ||
574 | int vpos, hpos, i; | ||
575 | s64 framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns; | ||
576 | bool invbl; | ||
577 | |||
578 | if (crtc < 0 || crtc >= dev->num_crtcs) { | ||
579 | DRM_ERROR("Invalid crtc %d\n", crtc); | ||
580 | return -EINVAL; | ||
581 | } | ||
582 | |||
583 | /* Scanout position query not supported? Should not happen. */ | ||
584 | if (!dev->driver->get_scanout_position) { | ||
585 | DRM_ERROR("Called from driver w/o get_scanout_position()!?\n"); | ||
586 | return -EIO; | ||
587 | } | ||
588 | |||
589 | mode = &refcrtc->hwmode; | ||
590 | vtotal = mode->crtc_vtotal; | ||
591 | vdisplay = mode->crtc_vdisplay; | ||
592 | |||
593 | /* Durations of frames, lines, pixels in nanoseconds. */ | ||
594 | framedur_ns = refcrtc->framedur_ns; | ||
595 | linedur_ns = refcrtc->linedur_ns; | ||
596 | pixeldur_ns = refcrtc->pixeldur_ns; | ||
597 | |||
598 | /* If mode timing undefined, just return as no-op: | ||
599 | * Happens during initial modesetting of a crtc. | ||
600 | */ | ||
601 | if (vtotal <= 0 || vdisplay <= 0 || framedur_ns == 0) { | ||
602 | DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc); | ||
603 | return -EAGAIN; | ||
604 | } | ||
605 | |||
606 | /* Don't know yet how to handle interlaced or | ||
607 | * double scan modes. Just no-op for now. | ||
608 | */ | ||
609 | if (mode->flags & (DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLSCAN)) { | ||
610 | DRM_DEBUG("crtc %d: Noop due to unsupported mode.\n", crtc); | ||
611 | return -ENOTSUPP; | ||
612 | } | ||
613 | |||
614 | /* Get current scanout position with system timestamp. | ||
615 | * Repeat query up to DRM_TIMESTAMP_MAXRETRIES times | ||
616 | * if single query takes longer than max_error nanoseconds. | ||
617 | * | ||
618 | * This guarantees a tight bound on maximum error if | ||
619 | * code gets preempted or delayed for some reason. | ||
620 | */ | ||
621 | for (i = 0; i < DRM_TIMESTAMP_MAXRETRIES; i++) { | ||
622 | /* Disable preemption to make it very likely to | ||
623 | * succeed in the first iteration even on PREEMPT_RT kernel. | ||
624 | */ | ||
625 | preempt_disable(); | ||
626 | |||
627 | /* Get system timestamp before query. */ | ||
628 | do_gettimeofday(&stime); | ||
629 | |||
630 | /* Get vertical and horizontal scanout pos. vpos, hpos. */ | ||
631 | vbl_status = dev->driver->get_scanout_position(dev, crtc, &vpos, &hpos); | ||
632 | |||
633 | /* Get system timestamp after query. */ | ||
634 | do_gettimeofday(&raw_time); | ||
635 | |||
636 | preempt_enable(); | ||
637 | |||
638 | /* Return as no-op if scanout query unsupported or failed. */ | ||
639 | if (!(vbl_status & DRM_SCANOUTPOS_VALID)) { | ||
640 | DRM_DEBUG("crtc %d : scanoutpos query failed [%d].\n", | ||
641 | crtc, vbl_status); | ||
642 | return -EIO; | ||
643 | } | ||
644 | |||
645 | duration_ns = timeval_to_ns(&raw_time) - timeval_to_ns(&stime); | ||
646 | |||
647 | /* Accept result with < max_error nsecs timing uncertainty. */ | ||
648 | if (duration_ns <= (s64) *max_error) | ||
649 | break; | ||
650 | } | ||
651 | |||
652 | /* Noisy system timing? */ | ||
653 | if (i == DRM_TIMESTAMP_MAXRETRIES) { | ||
654 | DRM_DEBUG("crtc %d: Noisy timestamp %d us > %d us [%d reps].\n", | ||
655 | crtc, (int) duration_ns/1000, *max_error/1000, i); | ||
656 | } | ||
657 | |||
658 | /* Return upper bound of timestamp precision error. */ | ||
659 | *max_error = (int) duration_ns; | ||
660 | |||
661 | /* Check if in vblank area: | ||
662 | * vpos is >=0 in video scanout area, but negative | ||
663 | * within vblank area, counting down the number of lines until | ||
664 | * start of scanout. | ||
665 | */ | ||
666 | invbl = vbl_status & DRM_SCANOUTPOS_INVBL; | ||
667 | |||
668 | /* Convert scanout position into elapsed time at raw_time query | ||
669 | * since start of scanout at first display scanline. delta_ns | ||
670 | * can be negative if start of scanout hasn't happened yet. | ||
671 | */ | ||
672 | delta_ns = (s64) vpos * linedur_ns + (s64) hpos * pixeldur_ns; | ||
673 | |||
674 | /* Is vpos outside nominal vblank area, but less than | ||
675 | * 1/100 of a frame height away from start of vblank? | ||
676 | * If so, assume this isn't a massively delayed vblank | ||
677 | * interrupt, but a vblank interrupt that fired a few | ||
678 | * microseconds before true start of vblank. Compensate | ||
679 | * by adding a full frame duration to the final timestamp. | ||
680 | * Happens, e.g., on ATI R500, R600. | ||
681 | * | ||
682 | * We only do this if DRM_CALLED_FROM_VBLIRQ. | ||
683 | */ | ||
684 | if ((flags & DRM_CALLED_FROM_VBLIRQ) && !invbl && | ||
685 | ((vdisplay - vpos) < vtotal / 100)) { | ||
686 | delta_ns = delta_ns - framedur_ns; | ||
687 | |||
688 | /* Signal this correction as "applied". */ | ||
689 | vbl_status |= 0x8; | ||
690 | } | ||
691 | |||
692 | /* Subtract time delta from raw timestamp to get final | ||
693 | * vblank_time timestamp for end of vblank. | ||
694 | */ | ||
695 | *vblank_time = ns_to_timeval(timeval_to_ns(&raw_time) - delta_ns); | ||
696 | |||
697 | DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %d.%d -> %d.%d [e %d us, %d rep]\n", | ||
698 | crtc, (int) vbl_status, hpos, vpos, raw_time.tv_sec, | ||
699 | raw_time.tv_usec, vblank_time->tv_sec, vblank_time->tv_usec, | ||
700 | (int) duration_ns/1000, i); | ||
701 | |||
702 | vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD; | ||
703 | if (invbl) | ||
704 | vbl_status |= DRM_VBLANKTIME_INVBL; | ||
705 | |||
706 | return vbl_status; | ||
707 | } | ||
708 | EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos); | ||
709 | |||
710 | /** | ||
711 | * drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent | ||
712 | * vblank interval. | ||
713 | * | ||
714 | * @dev: DRM device | ||
715 | * @crtc: which crtc's vblank timestamp to retrieve | ||
716 | * @tvblank: Pointer to target struct timeval which should receive the timestamp | ||
717 | * @flags: Flags to pass to driver: | ||
718 | * 0 = Default. | ||
719 | * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler. | ||
720 | * | ||
721 | * Fetches the system timestamp corresponding to the time of the most recent | ||
722 | * vblank interval on specified crtc. May call into kms-driver to | ||
723 | * compute the timestamp with a high-precision GPU specific method. | ||
724 | * | ||
725 | * Returns zero if timestamp originates from uncorrected do_gettimeofday() | ||
726 | * call, i.e., it isn't very precisely locked to the true vblank. | ||
727 | * | ||
728 | * Returns non-zero if timestamp is considered to be very precise. | ||
729 | */ | ||
730 | u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, | ||
731 | struct timeval *tvblank, unsigned flags) | ||
732 | { | ||
733 | int ret = 0; | ||
734 | |||
735 | /* Define requested maximum error on timestamps (nanoseconds). */ | ||
736 | int max_error = (int) drm_timestamp_precision * 1000; | ||
737 | |||
738 | /* Query driver if possible and precision timestamping enabled. */ | ||
739 | if (dev->driver->get_vblank_timestamp && (max_error > 0)) { | ||
740 | ret = dev->driver->get_vblank_timestamp(dev, crtc, &max_error, | ||
741 | tvblank, flags); | ||
742 | if (ret > 0) | ||
743 | return (u32) ret; | ||
744 | } | ||
745 | |||
746 | /* GPU high precision timestamp query unsupported or failed. | ||
747 | * Return gettimeofday timestamp as best estimate. | ||
748 | */ | ||
749 | do_gettimeofday(tvblank); | ||
750 | |||
751 | return 0; | ||
752 | } | ||
753 | EXPORT_SYMBOL(drm_get_last_vbltimestamp); | ||
754 | |||
755 | /** | ||
363 | * drm_vblank_count - retrieve "cooked" vblank counter value | 756 | * drm_vblank_count - retrieve "cooked" vblank counter value |
364 | * @dev: DRM device | 757 | * @dev: DRM device |
365 | * @crtc: which counter to retrieve | 758 | * @crtc: which counter to retrieve |
@@ -375,6 +768,40 @@ u32 drm_vblank_count(struct drm_device *dev, int crtc) | |||
375 | EXPORT_SYMBOL(drm_vblank_count); | 768 | EXPORT_SYMBOL(drm_vblank_count); |
376 | 769 | ||
377 | /** | 770 | /** |
771 | * drm_vblank_count_and_time - retrieve "cooked" vblank counter value | ||
772 | * and the system timestamp corresponding to that vblank counter value. | ||
773 | * | ||
774 | * @dev: DRM device | ||
775 | * @crtc: which counter to retrieve | ||
776 | * @vblanktime: Pointer to struct timeval to receive the vblank timestamp. | ||
777 | * | ||
778 | * Fetches the "cooked" vblank count value that represents the number of | ||
779 | * vblank events since the system was booted, including lost events due to | ||
780 | * modesetting activity. Returns corresponding system timestamp of the time | ||
781 | * of the vblank interval that corresponds to the current value vblank counter | ||
782 | * value. | ||
783 | */ | ||
784 | u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, | ||
785 | struct timeval *vblanktime) | ||
786 | { | ||
787 | u32 cur_vblank; | ||
788 | |||
789 | /* Read timestamp from slot of _vblank_time ringbuffer | ||
790 | * that corresponds to current vblank count. Retry if | ||
791 | * count has incremented during readout. This works like | ||
792 | * a seqlock. | ||
793 | */ | ||
794 | do { | ||
795 | cur_vblank = atomic_read(&dev->_vblank_count[crtc]); | ||
796 | *vblanktime = vblanktimestamp(dev, crtc, cur_vblank); | ||
797 | smp_rmb(); | ||
798 | } while (cur_vblank != atomic_read(&dev->_vblank_count[crtc])); | ||
799 | |||
800 | return cur_vblank; | ||
801 | } | ||
802 | EXPORT_SYMBOL(drm_vblank_count_and_time); | ||
803 | |||
804 | /** | ||
378 | * drm_update_vblank_count - update the master vblank counter | 805 | * drm_update_vblank_count - update the master vblank counter |
379 | * @dev: DRM device | 806 | * @dev: DRM device |
380 | * @crtc: counter to update | 807 | * @crtc: counter to update |
@@ -392,7 +819,8 @@ EXPORT_SYMBOL(drm_vblank_count); | |||
392 | */ | 819 | */ |
393 | static void drm_update_vblank_count(struct drm_device *dev, int crtc) | 820 | static void drm_update_vblank_count(struct drm_device *dev, int crtc) |
394 | { | 821 | { |
395 | u32 cur_vblank, diff; | 822 | u32 cur_vblank, diff, tslot, rc; |
823 | struct timeval t_vblank; | ||
396 | 824 | ||
397 | /* | 825 | /* |
398 | * Interrupts were disabled prior to this call, so deal with counter | 826 | * Interrupts were disabled prior to this call, so deal with counter |
@@ -400,8 +828,18 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc) | |||
400 | * NOTE! It's possible we lost a full dev->max_vblank_count events | 828 | * NOTE! It's possible we lost a full dev->max_vblank_count events |
401 | * here if the register is small or we had vblank interrupts off for | 829 | * here if the register is small or we had vblank interrupts off for |
402 | * a long time. | 830 | * a long time. |
831 | * | ||
832 | * We repeat the hardware vblank counter & timestamp query until | ||
833 | * we get consistent results. This to prevent races between gpu | ||
834 | * updating its hardware counter while we are retrieving the | ||
835 | * corresponding vblank timestamp. | ||
403 | */ | 836 | */ |
404 | cur_vblank = dev->driver->get_vblank_counter(dev, crtc); | 837 | do { |
838 | cur_vblank = dev->driver->get_vblank_counter(dev, crtc); | ||
839 | rc = drm_get_last_vbltimestamp(dev, crtc, &t_vblank, 0); | ||
840 | } while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc)); | ||
841 | |||
842 | /* Deal with counter wrap */ | ||
405 | diff = cur_vblank - dev->last_vblank[crtc]; | 843 | diff = cur_vblank - dev->last_vblank[crtc]; |
406 | if (cur_vblank < dev->last_vblank[crtc]) { | 844 | if (cur_vblank < dev->last_vblank[crtc]) { |
407 | diff += dev->max_vblank_count; | 845 | diff += dev->max_vblank_count; |
@@ -413,6 +851,16 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc) | |||
413 | DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", | 851 | DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", |
414 | crtc, diff); | 852 | crtc, diff); |
415 | 853 | ||
854 | /* Reinitialize corresponding vblank timestamp if high-precision query | ||
855 | * available. Skip this step if query unsupported or failed. Will | ||
856 | * reinitialize delayed at next vblank interrupt in that case. | ||
857 | */ | ||
858 | if (rc) { | ||
859 | tslot = atomic_read(&dev->_vblank_count[crtc]) + diff; | ||
860 | vblanktimestamp(dev, crtc, tslot) = t_vblank; | ||
861 | smp_wmb(); | ||
862 | } | ||
863 | |||
416 | atomic_add(diff, &dev->_vblank_count[crtc]); | 864 | atomic_add(diff, &dev->_vblank_count[crtc]); |
417 | } | 865 | } |
418 | 866 | ||
@@ -429,15 +877,27 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc) | |||
429 | */ | 877 | */ |
430 | int drm_vblank_get(struct drm_device *dev, int crtc) | 878 | int drm_vblank_get(struct drm_device *dev, int crtc) |
431 | { | 879 | { |
432 | unsigned long irqflags; | 880 | unsigned long irqflags, irqflags2; |
433 | int ret = 0; | 881 | int ret = 0; |
434 | 882 | ||
435 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 883 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
436 | /* Going from 0->1 means we have to enable interrupts again */ | 884 | /* Going from 0->1 means we have to enable interrupts again */ |
437 | if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) { | 885 | if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) { |
886 | /* Disable preemption while holding vblank_time_lock. Do | ||
887 | * it explicitely to guard against PREEMPT_RT kernel. | ||
888 | */ | ||
889 | preempt_disable(); | ||
890 | spin_lock_irqsave(&dev->vblank_time_lock, irqflags2); | ||
438 | if (!dev->vblank_enabled[crtc]) { | 891 | if (!dev->vblank_enabled[crtc]) { |
892 | /* Enable vblank irqs under vblank_time_lock protection. | ||
893 | * All vblank count & timestamp updates are held off | ||
894 | * until we are done reinitializing master counter and | ||
895 | * timestamps. Filtercode in drm_handle_vblank() will | ||
896 | * prevent double-accounting of same vblank interval. | ||
897 | */ | ||
439 | ret = dev->driver->enable_vblank(dev, crtc); | 898 | ret = dev->driver->enable_vblank(dev, crtc); |
440 | DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret); | 899 | DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", |
900 | crtc, ret); | ||
441 | if (ret) | 901 | if (ret) |
442 | atomic_dec(&dev->vblank_refcount[crtc]); | 902 | atomic_dec(&dev->vblank_refcount[crtc]); |
443 | else { | 903 | else { |
@@ -445,6 +905,8 @@ int drm_vblank_get(struct drm_device *dev, int crtc) | |||
445 | drm_update_vblank_count(dev, crtc); | 905 | drm_update_vblank_count(dev, crtc); |
446 | } | 906 | } |
447 | } | 907 | } |
908 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags2); | ||
909 | preempt_enable(); | ||
448 | } else { | 910 | } else { |
449 | if (!dev->vblank_enabled[crtc]) { | 911 | if (!dev->vblank_enabled[crtc]) { |
450 | atomic_dec(&dev->vblank_refcount[crtc]); | 912 | atomic_dec(&dev->vblank_refcount[crtc]); |
@@ -463,15 +925,17 @@ EXPORT_SYMBOL(drm_vblank_get); | |||
463 | * @crtc: which counter to give up | 925 | * @crtc: which counter to give up |
464 | * | 926 | * |
465 | * Release ownership of a given vblank counter, turning off interrupts | 927 | * Release ownership of a given vblank counter, turning off interrupts |
466 | * if possible. | 928 | * if possible. Disable interrupts after drm_vblank_offdelay milliseconds. |
467 | */ | 929 | */ |
468 | void drm_vblank_put(struct drm_device *dev, int crtc) | 930 | void drm_vblank_put(struct drm_device *dev, int crtc) |
469 | { | 931 | { |
470 | BUG_ON (atomic_read (&dev->vblank_refcount[crtc]) == 0); | 932 | BUG_ON(atomic_read(&dev->vblank_refcount[crtc]) == 0); |
471 | 933 | ||
472 | /* Last user schedules interrupt disable */ | 934 | /* Last user schedules interrupt disable */ |
473 | if (atomic_dec_and_test(&dev->vblank_refcount[crtc])) | 935 | if (atomic_dec_and_test(&dev->vblank_refcount[crtc]) && |
474 | mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ); | 936 | (drm_vblank_offdelay > 0)) |
937 | mod_timer(&dev->vblank_disable_timer, | ||
938 | jiffies + ((drm_vblank_offdelay * DRM_HZ)/1000)); | ||
475 | } | 939 | } |
476 | EXPORT_SYMBOL(drm_vblank_put); | 940 | EXPORT_SYMBOL(drm_vblank_put); |
477 | 941 | ||
@@ -480,10 +944,8 @@ void drm_vblank_off(struct drm_device *dev, int crtc) | |||
480 | unsigned long irqflags; | 944 | unsigned long irqflags; |
481 | 945 | ||
482 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 946 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
483 | dev->driver->disable_vblank(dev, crtc); | 947 | vblank_disable_and_save(dev, crtc); |
484 | DRM_WAKEUP(&dev->vbl_queue[crtc]); | 948 | DRM_WAKEUP(&dev->vbl_queue[crtc]); |
485 | dev->vblank_enabled[crtc] = 0; | ||
486 | dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc); | ||
487 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | 949 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
488 | } | 950 | } |
489 | EXPORT_SYMBOL(drm_vblank_off); | 951 | EXPORT_SYMBOL(drm_vblank_off); |
@@ -599,7 +1061,6 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, | |||
599 | e->base.file_priv = file_priv; | 1061 | e->base.file_priv = file_priv; |
600 | e->base.destroy = (void (*) (struct drm_pending_event *)) kfree; | 1062 | e->base.destroy = (void (*) (struct drm_pending_event *)) kfree; |
601 | 1063 | ||
602 | do_gettimeofday(&now); | ||
603 | spin_lock_irqsave(&dev->event_lock, flags); | 1064 | spin_lock_irqsave(&dev->event_lock, flags); |
604 | 1065 | ||
605 | if (file_priv->event_space < sizeof e->event) { | 1066 | if (file_priv->event_space < sizeof e->event) { |
@@ -609,7 +1070,8 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, | |||
609 | } | 1070 | } |
610 | 1071 | ||
611 | file_priv->event_space -= sizeof e->event; | 1072 | file_priv->event_space -= sizeof e->event; |
612 | seq = drm_vblank_count(dev, pipe); | 1073 | seq = drm_vblank_count_and_time(dev, pipe, &now); |
1074 | |||
613 | if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) && | 1075 | if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) && |
614 | (seq - vblwait->request.sequence) <= (1 << 23)) { | 1076 | (seq - vblwait->request.sequence) <= (1 << 23)) { |
615 | vblwait->request.sequence = seq + 1; | 1077 | vblwait->request.sequence = seq + 1; |
@@ -718,11 +1180,10 @@ int drm_wait_vblank(struct drm_device *dev, void *data, | |||
718 | if (ret != -EINTR) { | 1180 | if (ret != -EINTR) { |
719 | struct timeval now; | 1181 | struct timeval now; |
720 | 1182 | ||
721 | do_gettimeofday(&now); | 1183 | vblwait->reply.sequence = drm_vblank_count_and_time(dev, crtc, &now); |
722 | |||
723 | vblwait->reply.tval_sec = now.tv_sec; | 1184 | vblwait->reply.tval_sec = now.tv_sec; |
724 | vblwait->reply.tval_usec = now.tv_usec; | 1185 | vblwait->reply.tval_usec = now.tv_usec; |
725 | vblwait->reply.sequence = drm_vblank_count(dev, crtc); | 1186 | |
726 | DRM_DEBUG("returning %d to client\n", | 1187 | DRM_DEBUG("returning %d to client\n", |
727 | vblwait->reply.sequence); | 1188 | vblwait->reply.sequence); |
728 | } else { | 1189 | } else { |
@@ -741,8 +1202,7 @@ void drm_handle_vblank_events(struct drm_device *dev, int crtc) | |||
741 | unsigned long flags; | 1202 | unsigned long flags; |
742 | unsigned int seq; | 1203 | unsigned int seq; |
743 | 1204 | ||
744 | do_gettimeofday(&now); | 1205 | seq = drm_vblank_count_and_time(dev, crtc, &now); |
745 | seq = drm_vblank_count(dev, crtc); | ||
746 | 1206 | ||
747 | spin_lock_irqsave(&dev->event_lock, flags); | 1207 | spin_lock_irqsave(&dev->event_lock, flags); |
748 | 1208 | ||
@@ -780,11 +1240,64 @@ void drm_handle_vblank_events(struct drm_device *dev, int crtc) | |||
780 | */ | 1240 | */ |
781 | void drm_handle_vblank(struct drm_device *dev, int crtc) | 1241 | void drm_handle_vblank(struct drm_device *dev, int crtc) |
782 | { | 1242 | { |
1243 | u32 vblcount; | ||
1244 | s64 diff_ns; | ||
1245 | struct timeval tvblank; | ||
1246 | unsigned long irqflags; | ||
1247 | |||
783 | if (!dev->num_crtcs) | 1248 | if (!dev->num_crtcs) |
784 | return; | 1249 | return; |
785 | 1250 | ||
786 | atomic_inc(&dev->_vblank_count[crtc]); | 1251 | /* Need timestamp lock to prevent concurrent execution with |
1252 | * vblank enable/disable, as this would cause inconsistent | ||
1253 | * or corrupted timestamps and vblank counts. | ||
1254 | */ | ||
1255 | spin_lock_irqsave(&dev->vblank_time_lock, irqflags); | ||
1256 | |||
1257 | /* Vblank irq handling disabled. Nothing to do. */ | ||
1258 | if (!dev->vblank_enabled[crtc]) { | ||
1259 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); | ||
1260 | return; | ||
1261 | } | ||
1262 | |||
1263 | /* Fetch corresponding timestamp for this vblank interval from | ||
1264 | * driver and store it in proper slot of timestamp ringbuffer. | ||
1265 | */ | ||
1266 | |||
1267 | /* Get current timestamp and count. */ | ||
1268 | vblcount = atomic_read(&dev->_vblank_count[crtc]); | ||
1269 | drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ); | ||
1270 | |||
1271 | /* Compute time difference to timestamp of last vblank */ | ||
1272 | diff_ns = timeval_to_ns(&tvblank) - | ||
1273 | timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount)); | ||
1274 | |||
1275 | /* Update vblank timestamp and count if at least | ||
1276 | * DRM_REDUNDANT_VBLIRQ_THRESH_NS nanoseconds | ||
1277 | * difference between last stored timestamp and current | ||
1278 | * timestamp. A smaller difference means basically | ||
1279 | * identical timestamps. Happens if this vblank has | ||
1280 | * been already processed and this is a redundant call, | ||
1281 | * e.g., due to spurious vblank interrupts. We need to | ||
1282 | * ignore those for accounting. | ||
1283 | */ | ||
1284 | if (abs(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS) { | ||
1285 | /* Store new timestamp in ringbuffer. */ | ||
1286 | vblanktimestamp(dev, crtc, vblcount + 1) = tvblank; | ||
1287 | smp_wmb(); | ||
1288 | |||
1289 | /* Increment cooked vblank count. This also atomically commits | ||
1290 | * the timestamp computed above. | ||
1291 | */ | ||
1292 | atomic_inc(&dev->_vblank_count[crtc]); | ||
1293 | } else { | ||
1294 | DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n", | ||
1295 | crtc, (int) diff_ns); | ||
1296 | } | ||
1297 | |||
787 | DRM_WAKEUP(&dev->vbl_queue[crtc]); | 1298 | DRM_WAKEUP(&dev->vbl_queue[crtc]); |
788 | drm_handle_vblank_events(dev, crtc); | 1299 | drm_handle_vblank_events(dev, crtc); |
1300 | |||
1301 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); | ||
789 | } | 1302 | } |
790 | EXPORT_SYMBOL(drm_handle_vblank); | 1303 | EXPORT_SYMBOL(drm_handle_vblank); |
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index cdc89ee042cc..d59edc18301f 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c | |||
@@ -40,12 +40,22 @@ | |||
40 | unsigned int drm_debug = 0; /* 1 to enable debug output */ | 40 | unsigned int drm_debug = 0; /* 1 to enable debug output */ |
41 | EXPORT_SYMBOL(drm_debug); | 41 | EXPORT_SYMBOL(drm_debug); |
42 | 42 | ||
43 | unsigned int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */ | ||
44 | EXPORT_SYMBOL(drm_vblank_offdelay); | ||
45 | |||
46 | unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ | ||
47 | EXPORT_SYMBOL(drm_timestamp_precision); | ||
48 | |||
43 | MODULE_AUTHOR(CORE_AUTHOR); | 49 | MODULE_AUTHOR(CORE_AUTHOR); |
44 | MODULE_DESCRIPTION(CORE_DESC); | 50 | MODULE_DESCRIPTION(CORE_DESC); |
45 | MODULE_LICENSE("GPL and additional rights"); | 51 | MODULE_LICENSE("GPL and additional rights"); |
46 | MODULE_PARM_DESC(debug, "Enable debug output"); | 52 | MODULE_PARM_DESC(debug, "Enable debug output"); |
53 | MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs]"); | ||
54 | MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]"); | ||
47 | 55 | ||
48 | module_param_named(debug, drm_debug, int, 0600); | 56 | module_param_named(debug, drm_debug, int, 0600); |
57 | module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600); | ||
58 | module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); | ||
49 | 59 | ||
50 | struct idr drm_minors_idr; | 60 | struct idr drm_minors_idr; |
51 | 61 | ||
diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 274eaaa15c36..2b3398004aa5 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h | |||
@@ -683,6 +683,21 @@ struct drm_master { | |||
683 | void *driver_priv; /**< Private structure for driver to use */ | 683 | void *driver_priv; /**< Private structure for driver to use */ |
684 | }; | 684 | }; |
685 | 685 | ||
686 | /* Size of ringbuffer for vblank timestamps. Just double-buffer | ||
687 | * in initial implementation. | ||
688 | */ | ||
689 | #define DRM_VBLANKTIME_RBSIZE 2 | ||
690 | |||
691 | /* Flags and return codes for get_vblank_timestamp() driver function. */ | ||
692 | #define DRM_CALLED_FROM_VBLIRQ 1 | ||
693 | #define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0) | ||
694 | #define DRM_VBLANKTIME_INVBL (1 << 1) | ||
695 | |||
696 | /* get_scanout_position() return flags */ | ||
697 | #define DRM_SCANOUTPOS_VALID (1 << 0) | ||
698 | #define DRM_SCANOUTPOS_INVBL (1 << 1) | ||
699 | #define DRM_SCANOUTPOS_ACCURATE (1 << 2) | ||
700 | |||
686 | /** | 701 | /** |
687 | * DRM driver structure. This structure represent the common code for | 702 | * DRM driver structure. This structure represent the common code for |
688 | * a family of cards. There will one drm_device for each card present | 703 | * a family of cards. There will one drm_device for each card present |
@@ -760,6 +775,68 @@ struct drm_driver { | |||
760 | */ | 775 | */ |
761 | int (*device_is_agp) (struct drm_device *dev); | 776 | int (*device_is_agp) (struct drm_device *dev); |
762 | 777 | ||
778 | /** | ||
779 | * Called by vblank timestamping code. | ||
780 | * | ||
781 | * Return the current display scanout position from a crtc. | ||
782 | * | ||
783 | * \param dev DRM device. | ||
784 | * \param crtc Id of the crtc to query. | ||
785 | * \param *vpos Target location for current vertical scanout position. | ||
786 | * \param *hpos Target location for current horizontal scanout position. | ||
787 | * | ||
788 | * Returns vpos as a positive number while in active scanout area. | ||
789 | * Returns vpos as a negative number inside vblank, counting the number | ||
790 | * of scanlines to go until end of vblank, e.g., -1 means "one scanline | ||
791 | * until start of active scanout / end of vblank." | ||
792 | * | ||
793 | * \return Flags, or'ed together as follows: | ||
794 | * | ||
795 | * DRM_SCANOUTPOS_VALID = Query successfull. | ||
796 | * DRM_SCANOUTPOS_INVBL = Inside vblank. | ||
797 | * DRM_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of | ||
798 | * this flag means that returned position may be offset by a constant | ||
799 | * but unknown small number of scanlines wrt. real scanout position. | ||
800 | * | ||
801 | */ | ||
802 | int (*get_scanout_position) (struct drm_device *dev, int crtc, | ||
803 | int *vpos, int *hpos); | ||
804 | |||
805 | /** | ||
806 | * Called by \c drm_get_last_vbltimestamp. Should return a precise | ||
807 | * timestamp when the most recent VBLANK interval ended or will end. | ||
808 | * | ||
809 | * Specifically, the timestamp in @vblank_time should correspond as | ||
810 | * closely as possible to the time when the first video scanline of | ||
811 | * the video frame after the end of VBLANK will start scanning out, | ||
812 | * the time immmediately after end of the VBLANK interval. If the | ||
813 | * @crtc is currently inside VBLANK, this will be a time in the future. | ||
814 | * If the @crtc is currently scanning out a frame, this will be the | ||
815 | * past start time of the current scanout. This is meant to adhere | ||
816 | * to the OpenML OML_sync_control extension specification. | ||
817 | * | ||
818 | * \param dev dev DRM device handle. | ||
819 | * \param crtc crtc for which timestamp should be returned. | ||
820 | * \param *max_error Maximum allowable timestamp error in nanoseconds. | ||
821 | * Implementation should strive to provide timestamp | ||
822 | * with an error of at most *max_error nanoseconds. | ||
823 | * Returns true upper bound on error for timestamp. | ||
824 | * \param *vblank_time Target location for returned vblank timestamp. | ||
825 | * \param flags 0 = Defaults, no special treatment needed. | ||
826 | * \param DRM_CALLED_FROM_VBLIRQ = Function is called from vblank | ||
827 | * irq handler. Some drivers need to apply some workarounds | ||
828 | * for gpu-specific vblank irq quirks if flag is set. | ||
829 | * | ||
830 | * \returns | ||
831 | * Zero if timestamping isn't supported in current display mode or a | ||
832 | * negative number on failure. A positive status code on success, | ||
833 | * which describes how the vblank_time timestamp was computed. | ||
834 | */ | ||
835 | int (*get_vblank_timestamp) (struct drm_device *dev, int crtc, | ||
836 | int *max_error, | ||
837 | struct timeval *vblank_time, | ||
838 | unsigned flags); | ||
839 | |||
763 | /* these have to be filled in */ | 840 | /* these have to be filled in */ |
764 | 841 | ||
765 | irqreturn_t(*irq_handler) (DRM_IRQ_ARGS); | 842 | irqreturn_t(*irq_handler) (DRM_IRQ_ARGS); |
@@ -983,6 +1060,8 @@ struct drm_device { | |||
983 | 1060 | ||
984 | wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */ | 1061 | wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */ |
985 | atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ | 1062 | atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ |
1063 | struct timeval *_vblank_time; /**< timestamp of current vblank_count (drivers must alloc right number of fields) */ | ||
1064 | spinlock_t vblank_time_lock; /**< Protects vblank count and time updates during vblank enable/disable */ | ||
986 | spinlock_t vbl_lock; | 1065 | spinlock_t vbl_lock; |
987 | atomic_t *vblank_refcount; /* number of users of vblank interruptsper crtc */ | 1066 | atomic_t *vblank_refcount; /* number of users of vblank interruptsper crtc */ |
988 | u32 *last_vblank; /* protected by dev->vbl_lock, used */ | 1067 | u32 *last_vblank; /* protected by dev->vbl_lock, used */ |
@@ -1284,11 +1363,22 @@ extern int drm_wait_vblank(struct drm_device *dev, void *data, | |||
1284 | struct drm_file *filp); | 1363 | struct drm_file *filp); |
1285 | extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); | 1364 | extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); |
1286 | extern u32 drm_vblank_count(struct drm_device *dev, int crtc); | 1365 | extern u32 drm_vblank_count(struct drm_device *dev, int crtc); |
1366 | extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, | ||
1367 | struct timeval *vblanktime); | ||
1287 | extern void drm_handle_vblank(struct drm_device *dev, int crtc); | 1368 | extern void drm_handle_vblank(struct drm_device *dev, int crtc); |
1288 | extern int drm_vblank_get(struct drm_device *dev, int crtc); | 1369 | extern int drm_vblank_get(struct drm_device *dev, int crtc); |
1289 | extern void drm_vblank_put(struct drm_device *dev, int crtc); | 1370 | extern void drm_vblank_put(struct drm_device *dev, int crtc); |
1290 | extern void drm_vblank_off(struct drm_device *dev, int crtc); | 1371 | extern void drm_vblank_off(struct drm_device *dev, int crtc); |
1291 | extern void drm_vblank_cleanup(struct drm_device *dev); | 1372 | extern void drm_vblank_cleanup(struct drm_device *dev); |
1373 | extern u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, | ||
1374 | struct timeval *tvblank, unsigned flags); | ||
1375 | extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, | ||
1376 | int crtc, int *max_error, | ||
1377 | struct timeval *vblank_time, | ||
1378 | unsigned flags, | ||
1379 | struct drm_crtc *refcrtc); | ||
1380 | extern void drm_calc_timestamping_constants(struct drm_crtc *crtc); | ||
1381 | |||
1292 | /* Modesetting support */ | 1382 | /* Modesetting support */ |
1293 | extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc); | 1383 | extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc); |
1294 | extern void drm_vblank_post_modeset(struct drm_device *dev, int crtc); | 1384 | extern void drm_vblank_post_modeset(struct drm_device *dev, int crtc); |
@@ -1340,6 +1430,9 @@ extern void drm_put_dev(struct drm_device *dev); | |||
1340 | extern int drm_put_minor(struct drm_minor **minor); | 1430 | extern int drm_put_minor(struct drm_minor **minor); |
1341 | extern unsigned int drm_debug; | 1431 | extern unsigned int drm_debug; |
1342 | 1432 | ||
1433 | extern unsigned int drm_vblank_offdelay; | ||
1434 | extern unsigned int drm_timestamp_precision; | ||
1435 | |||
1343 | extern struct class *drm_class; | 1436 | extern struct class *drm_class; |
1344 | extern struct proc_dir_entry *drm_proc_root; | 1437 | extern struct proc_dir_entry *drm_proc_root; |
1345 | extern struct dentry *drm_debugfs_root; | 1438 | extern struct dentry *drm_debugfs_root; |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 029aa688e787..acd7fade160d 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -351,8 +351,14 @@ struct drm_crtc { | |||
351 | 351 | ||
352 | bool enabled; | 352 | bool enabled; |
353 | 353 | ||
354 | /* Requested mode from modesetting. */ | ||
354 | struct drm_display_mode mode; | 355 | struct drm_display_mode mode; |
355 | 356 | ||
357 | /* Programmed mode in hw, after adjustments for encoders, | ||
358 | * crtc, panel scaling etc. Needed for timestamping etc. | ||
359 | */ | ||
360 | struct drm_display_mode hwmode; | ||
361 | |||
356 | int x, y; | 362 | int x, y; |
357 | const struct drm_crtc_funcs *funcs; | 363 | const struct drm_crtc_funcs *funcs; |
358 | 364 | ||
@@ -360,6 +366,9 @@ struct drm_crtc { | |||
360 | uint32_t gamma_size; | 366 | uint32_t gamma_size; |
361 | uint16_t *gamma_store; | 367 | uint16_t *gamma_store; |
362 | 368 | ||
369 | /* Constants needed for precise vblank and swap timestamping. */ | ||
370 | s64 framedur_ns, linedur_ns, pixeldur_ns; | ||
371 | |||
363 | /* if you are using the helper */ | 372 | /* if you are using the helper */ |
364 | void *helper_private; | 373 | void *helper_private; |
365 | }; | 374 | }; |