diff options
-rw-r--r-- | drivers/gpu/drm/drm_crtc_helper.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_irq.c | 109 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 91 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 29 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_atombios.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_display.c | 29 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_drv.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_kms.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_mode.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_pm.c | 2 | ||||
-rw-r--r-- | include/drm/drmP.h | 8 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 2 |
12 files changed, 144 insertions, 138 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 01361aba033b..245fe4fa9c9e 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
@@ -536,7 +536,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, | |||
536 | * are later needed by vblank and swap-completion | 536 | * are later needed by vblank and swap-completion |
537 | * timestamping. They are derived from true hwmode. | 537 | * timestamping. They are derived from true hwmode. |
538 | */ | 538 | */ |
539 | drm_calc_timestamping_constants(crtc); | 539 | drm_calc_timestamping_constants(crtc, &crtc->hwmode); |
540 | 540 | ||
541 | /* FIXME: add subpixel order */ | 541 | /* FIXME: add subpixel order */ |
542 | done: | 542 | done: |
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index e7de2da57234..c2676b5908d9 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c | |||
@@ -436,45 +436,41 @@ int drm_control(struct drm_device *dev, void *data, | |||
436 | } | 436 | } |
437 | 437 | ||
438 | /** | 438 | /** |
439 | * drm_calc_timestamping_constants - Calculate and | 439 | * drm_calc_timestamping_constants - Calculate vblank timestamp constants |
440 | * store various constants which are later needed by | ||
441 | * vblank and swap-completion timestamping, e.g, by | ||
442 | * drm_calc_vbltimestamp_from_scanoutpos(). | ||
443 | * They are derived from crtc's true scanout timing, | ||
444 | * so they take things like panel scaling or other | ||
445 | * adjustments into account. | ||
446 | * | 440 | * |
447 | * @crtc drm_crtc whose timestamp constants should be updated. | 441 | * @crtc drm_crtc whose timestamp constants should be updated. |
442 | * @mode display mode containing the scanout timings | ||
448 | * | 443 | * |
444 | * Calculate and store various constants which are later | ||
445 | * needed by vblank and swap-completion timestamping, e.g, | ||
446 | * by drm_calc_vbltimestamp_from_scanoutpos(). They are | ||
447 | * derived from crtc's true scanout timing, so they take | ||
448 | * things like panel scaling or other adjustments into account. | ||
449 | */ | 449 | */ |
450 | void drm_calc_timestamping_constants(struct drm_crtc *crtc) | 450 | void drm_calc_timestamping_constants(struct drm_crtc *crtc, |
451 | const struct drm_display_mode *mode) | ||
451 | { | 452 | { |
452 | s64 linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0; | 453 | int linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0; |
453 | u64 dotclock; | 454 | int dotclock = mode->crtc_clock; |
454 | |||
455 | /* Dot clock in Hz: */ | ||
456 | dotclock = (u64) crtc->hwmode.clock * 1000; | ||
457 | |||
458 | /* Fields of interlaced scanout modes are only half a frame duration. | ||
459 | * Double the dotclock to get half the frame-/line-/pixelduration. | ||
460 | */ | ||
461 | if (crtc->hwmode.flags & DRM_MODE_FLAG_INTERLACE) | ||
462 | dotclock *= 2; | ||
463 | 455 | ||
464 | /* Valid dotclock? */ | 456 | /* Valid dotclock? */ |
465 | if (dotclock > 0) { | 457 | if (dotclock > 0) { |
466 | int frame_size; | 458 | int frame_size = mode->crtc_htotal * mode->crtc_vtotal; |
467 | /* Convert scanline length in pixels and video dot clock to | 459 | |
468 | * line duration, frame duration and pixel duration in | 460 | /* |
469 | * nanoseconds: | 461 | * Convert scanline length in pixels and video |
462 | * dot clock to line duration, frame duration | ||
463 | * and pixel duration in nanoseconds: | ||
470 | */ | 464 | */ |
471 | pixeldur_ns = (s64) div64_u64(1000000000, dotclock); | 465 | pixeldur_ns = 1000000 / dotclock; |
472 | linedur_ns = (s64) div64_u64(((u64) crtc->hwmode.crtc_htotal * | 466 | linedur_ns = div_u64((u64) mode->crtc_htotal * 1000000, dotclock); |
473 | 1000000000), dotclock); | 467 | framedur_ns = div_u64((u64) frame_size * 1000000, dotclock); |
474 | frame_size = crtc->hwmode.crtc_htotal * | 468 | |
475 | crtc->hwmode.crtc_vtotal; | 469 | /* |
476 | framedur_ns = (s64) div64_u64((u64) frame_size * 1000000000, | 470 | * Fields of interlaced scanout modes are only half a frame duration. |
477 | dotclock); | 471 | */ |
472 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) | ||
473 | framedur_ns /= 2; | ||
478 | } else | 474 | } else |
479 | DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n", | 475 | DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n", |
480 | crtc->base.id); | 476 | crtc->base.id); |
@@ -484,11 +480,11 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc) | |||
484 | crtc->framedur_ns = framedur_ns; | 480 | crtc->framedur_ns = framedur_ns; |
485 | 481 | ||
486 | DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n", | 482 | DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n", |
487 | crtc->base.id, crtc->hwmode.crtc_htotal, | 483 | crtc->base.id, mode->crtc_htotal, |
488 | crtc->hwmode.crtc_vtotal, crtc->hwmode.crtc_vdisplay); | 484 | mode->crtc_vtotal, mode->crtc_vdisplay); |
489 | DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n", | 485 | DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n", |
490 | crtc->base.id, (int) dotclock/1000, (int) framedur_ns, | 486 | crtc->base.id, dotclock, framedur_ns, |
491 | (int) linedur_ns, (int) pixeldur_ns); | 487 | linedur_ns, pixeldur_ns); |
492 | } | 488 | } |
493 | EXPORT_SYMBOL(drm_calc_timestamping_constants); | 489 | EXPORT_SYMBOL(drm_calc_timestamping_constants); |
494 | 490 | ||
@@ -521,6 +517,7 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants); | |||
521 | * 0 = Default. | 517 | * 0 = Default. |
522 | * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler. | 518 | * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler. |
523 | * @refcrtc: drm_crtc* of crtc which defines scanout timing. | 519 | * @refcrtc: drm_crtc* of crtc which defines scanout timing. |
520 | * @mode: mode which defines the scanout timings | ||
524 | * | 521 | * |
525 | * Returns negative value on error, failure or if not supported in current | 522 | * Returns negative value on error, failure or if not supported in current |
526 | * video mode: | 523 | * video mode: |
@@ -540,14 +537,14 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, | |||
540 | int *max_error, | 537 | int *max_error, |
541 | struct timeval *vblank_time, | 538 | struct timeval *vblank_time, |
542 | unsigned flags, | 539 | unsigned flags, |
543 | struct drm_crtc *refcrtc) | 540 | const struct drm_crtc *refcrtc, |
541 | const struct drm_display_mode *mode) | ||
544 | { | 542 | { |
545 | ktime_t stime, etime, mono_time_offset; | 543 | ktime_t stime, etime, mono_time_offset; |
546 | struct timeval tv_etime; | 544 | struct timeval tv_etime; |
547 | struct drm_display_mode *mode; | 545 | int vbl_status; |
548 | int vbl_status, vtotal, vdisplay; | ||
549 | int vpos, hpos, i; | 546 | int vpos, hpos, i; |
550 | s64 framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns; | 547 | int framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns; |
551 | bool invbl; | 548 | bool invbl; |
552 | 549 | ||
553 | if (crtc < 0 || crtc >= dev->num_crtcs) { | 550 | if (crtc < 0 || crtc >= dev->num_crtcs) { |
@@ -561,10 +558,6 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, | |||
561 | return -EIO; | 558 | return -EIO; |
562 | } | 559 | } |
563 | 560 | ||
564 | mode = &refcrtc->hwmode; | ||
565 | vtotal = mode->crtc_vtotal; | ||
566 | vdisplay = mode->crtc_vdisplay; | ||
567 | |||
568 | /* Durations of frames, lines, pixels in nanoseconds. */ | 561 | /* Durations of frames, lines, pixels in nanoseconds. */ |
569 | framedur_ns = refcrtc->framedur_ns; | 562 | framedur_ns = refcrtc->framedur_ns; |
570 | linedur_ns = refcrtc->linedur_ns; | 563 | linedur_ns = refcrtc->linedur_ns; |
@@ -573,7 +566,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, | |||
573 | /* If mode timing undefined, just return as no-op: | 566 | /* If mode timing undefined, just return as no-op: |
574 | * Happens during initial modesetting of a crtc. | 567 | * Happens during initial modesetting of a crtc. |
575 | */ | 568 | */ |
576 | if (vtotal <= 0 || vdisplay <= 0 || framedur_ns == 0) { | 569 | if (framedur_ns == 0) { |
577 | DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc); | 570 | DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc); |
578 | return -EAGAIN; | 571 | return -EAGAIN; |
579 | } | 572 | } |
@@ -590,7 +583,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, | |||
590 | * Get vertical and horizontal scanout position vpos, hpos, | 583 | * Get vertical and horizontal scanout position vpos, hpos, |
591 | * and bounding timestamps stime, etime, pre/post query. | 584 | * and bounding timestamps stime, etime, pre/post query. |
592 | */ | 585 | */ |
593 | vbl_status = dev->driver->get_scanout_position(dev, crtc, &vpos, | 586 | vbl_status = dev->driver->get_scanout_position(dev, crtc, flags, &vpos, |
594 | &hpos, &stime, &etime); | 587 | &hpos, &stime, &etime); |
595 | 588 | ||
596 | /* | 589 | /* |
@@ -611,18 +604,18 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, | |||
611 | duration_ns = ktime_to_ns(etime) - ktime_to_ns(stime); | 604 | duration_ns = ktime_to_ns(etime) - ktime_to_ns(stime); |
612 | 605 | ||
613 | /* Accept result with < max_error nsecs timing uncertainty. */ | 606 | /* Accept result with < max_error nsecs timing uncertainty. */ |
614 | if (duration_ns <= (s64) *max_error) | 607 | if (duration_ns <= *max_error) |
615 | break; | 608 | break; |
616 | } | 609 | } |
617 | 610 | ||
618 | /* Noisy system timing? */ | 611 | /* Noisy system timing? */ |
619 | if (i == DRM_TIMESTAMP_MAXRETRIES) { | 612 | if (i == DRM_TIMESTAMP_MAXRETRIES) { |
620 | DRM_DEBUG("crtc %d: Noisy timestamp %d us > %d us [%d reps].\n", | 613 | DRM_DEBUG("crtc %d: Noisy timestamp %d us > %d us [%d reps].\n", |
621 | crtc, (int) duration_ns/1000, *max_error/1000, i); | 614 | crtc, duration_ns/1000, *max_error/1000, i); |
622 | } | 615 | } |
623 | 616 | ||
624 | /* Return upper bound of timestamp precision error. */ | 617 | /* Return upper bound of timestamp precision error. */ |
625 | *max_error = (int) duration_ns; | 618 | *max_error = duration_ns; |
626 | 619 | ||
627 | /* Check if in vblank area: | 620 | /* Check if in vblank area: |
628 | * vpos is >=0 in video scanout area, but negative | 621 | * vpos is >=0 in video scanout area, but negative |
@@ -635,25 +628,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, | |||
635 | * since start of scanout at first display scanline. delta_ns | 628 | * since start of scanout at first display scanline. delta_ns |
636 | * can be negative if start of scanout hasn't happened yet. | 629 | * can be negative if start of scanout hasn't happened yet. |
637 | */ | 630 | */ |
638 | delta_ns = (s64) vpos * linedur_ns + (s64) hpos * pixeldur_ns; | 631 | delta_ns = vpos * linedur_ns + hpos * pixeldur_ns; |
639 | |||
640 | /* Is vpos outside nominal vblank area, but less than | ||
641 | * 1/100 of a frame height away from start of vblank? | ||
642 | * If so, assume this isn't a massively delayed vblank | ||
643 | * interrupt, but a vblank interrupt that fired a few | ||
644 | * microseconds before true start of vblank. Compensate | ||
645 | * by adding a full frame duration to the final timestamp. | ||
646 | * Happens, e.g., on ATI R500, R600. | ||
647 | * | ||
648 | * We only do this if DRM_CALLED_FROM_VBLIRQ. | ||
649 | */ | ||
650 | if ((flags & DRM_CALLED_FROM_VBLIRQ) && !invbl && | ||
651 | ((vdisplay - vpos) < vtotal / 100)) { | ||
652 | delta_ns = delta_ns - framedur_ns; | ||
653 | |||
654 | /* Signal this correction as "applied". */ | ||
655 | vbl_status |= 0x8; | ||
656 | } | ||
657 | 632 | ||
658 | if (!drm_timestamp_monotonic) | 633 | if (!drm_timestamp_monotonic) |
659 | etime = ktime_sub(etime, mono_time_offset); | 634 | etime = ktime_sub(etime, mono_time_offset); |
@@ -673,7 +648,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, | |||
673 | crtc, (int)vbl_status, hpos, vpos, | 648 | crtc, (int)vbl_status, hpos, vpos, |
674 | (long)tv_etime.tv_sec, (long)tv_etime.tv_usec, | 649 | (long)tv_etime.tv_sec, (long)tv_etime.tv_usec, |
675 | (long)vblank_time->tv_sec, (long)vblank_time->tv_usec, | 650 | (long)vblank_time->tv_sec, (long)vblank_time->tv_usec, |
676 | (int)duration_ns/1000, i); | 651 | duration_ns/1000, i); |
677 | 652 | ||
678 | vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD; | 653 | vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD; |
679 | if (invbl) | 654 | if (invbl) |
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 6d11e253218a..17d8fcb1b6f7 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
@@ -621,36 +621,15 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) | |||
621 | #define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__)) | 621 | #define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__)) |
622 | #define __raw_i915_read16(dev_priv__, reg__) readw((dev_priv__)->regs + (reg__)) | 622 | #define __raw_i915_read16(dev_priv__, reg__) readw((dev_priv__)->regs + (reg__)) |
623 | 623 | ||
624 | static bool intel_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe) | 624 | static bool ilk_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe) |
625 | { | 625 | { |
626 | struct drm_i915_private *dev_priv = dev->dev_private; | 626 | struct drm_i915_private *dev_priv = dev->dev_private; |
627 | uint32_t status; | 627 | uint32_t status; |
628 | int reg; | ||
629 | 628 | ||
630 | if (IS_VALLEYVIEW(dev)) { | 629 | if (INTEL_INFO(dev)->gen < 7) { |
631 | status = pipe == PIPE_A ? | ||
632 | I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT : | ||
633 | I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; | ||
634 | |||
635 | reg = VLV_ISR; | ||
636 | } else if (IS_GEN2(dev)) { | ||
637 | status = pipe == PIPE_A ? | ||
638 | I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT : | ||
639 | I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; | ||
640 | |||
641 | reg = ISR; | ||
642 | } else if (INTEL_INFO(dev)->gen < 5) { | ||
643 | status = pipe == PIPE_A ? | ||
644 | I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT : | ||
645 | I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; | ||
646 | |||
647 | reg = ISR; | ||
648 | } else if (INTEL_INFO(dev)->gen < 7) { | ||
649 | status = pipe == PIPE_A ? | 630 | status = pipe == PIPE_A ? |
650 | DE_PIPEA_VBLANK : | 631 | DE_PIPEA_VBLANK : |
651 | DE_PIPEB_VBLANK; | 632 | DE_PIPEB_VBLANK; |
652 | |||
653 | reg = DEISR; | ||
654 | } else { | 633 | } else { |
655 | switch (pipe) { | 634 | switch (pipe) { |
656 | default: | 635 | default: |
@@ -664,18 +643,14 @@ static bool intel_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe) | |||
664 | status = DE_PIPEC_VBLANK_IVB; | 643 | status = DE_PIPEC_VBLANK_IVB; |
665 | break; | 644 | break; |
666 | } | 645 | } |
667 | |||
668 | reg = DEISR; | ||
669 | } | 646 | } |
670 | 647 | ||
671 | if (IS_GEN2(dev)) | 648 | return __raw_i915_read32(dev_priv, DEISR) & status; |
672 | return __raw_i915_read16(dev_priv, reg) & status; | ||
673 | else | ||
674 | return __raw_i915_read32(dev_priv, reg) & status; | ||
675 | } | 649 | } |
676 | 650 | ||
677 | static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, | 651 | static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, |
678 | int *vpos, int *hpos, ktime_t *stime, ktime_t *etime) | 652 | unsigned int flags, int *vpos, int *hpos, |
653 | ktime_t *stime, ktime_t *etime) | ||
679 | { | 654 | { |
680 | struct drm_i915_private *dev_priv = dev->dev_private; | 655 | struct drm_i915_private *dev_priv = dev->dev_private; |
681 | struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; | 656 | struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; |
@@ -698,6 +673,12 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, | |||
698 | vbl_start = mode->crtc_vblank_start; | 673 | vbl_start = mode->crtc_vblank_start; |
699 | vbl_end = mode->crtc_vblank_end; | 674 | vbl_end = mode->crtc_vblank_end; |
700 | 675 | ||
676 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) { | ||
677 | vbl_start = DIV_ROUND_UP(vbl_start, 2); | ||
678 | vbl_end /= 2; | ||
679 | vtotal /= 2; | ||
680 | } | ||
681 | |||
701 | ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE; | 682 | ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE; |
702 | 683 | ||
703 | /* | 684 | /* |
@@ -722,17 +703,42 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, | |||
722 | else | 703 | else |
723 | position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3; | 704 | position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3; |
724 | 705 | ||
725 | /* | 706 | if (HAS_PCH_SPLIT(dev)) { |
726 | * The scanline counter increments at the leading edge | 707 | /* |
727 | * of hsync, ie. it completely misses the active portion | 708 | * The scanline counter increments at the leading edge |
728 | * of the line. Fix up the counter at both edges of vblank | 709 | * of hsync, ie. it completely misses the active portion |
729 | * to get a more accurate picture whether we're in vblank | 710 | * of the line. Fix up the counter at both edges of vblank |
730 | * or not. | 711 | * to get a more accurate picture whether we're in vblank |
731 | */ | 712 | * or not. |
732 | in_vbl = intel_pipe_in_vblank_locked(dev, pipe); | 713 | */ |
733 | if ((in_vbl && position == vbl_start - 1) || | 714 | in_vbl = ilk_pipe_in_vblank_locked(dev, pipe); |
734 | (!in_vbl && position == vbl_end - 1)) | 715 | if ((in_vbl && position == vbl_start - 1) || |
735 | position = (position + 1) % vtotal; | 716 | (!in_vbl && position == vbl_end - 1)) |
717 | position = (position + 1) % vtotal; | ||
718 | } else { | ||
719 | /* | ||
720 | * ISR vblank status bits don't work the way we'd want | ||
721 | * them to work on non-PCH platforms (for | ||
722 | * ilk_pipe_in_vblank_locked()), and there doesn't | ||
723 | * appear any other way to determine if we're currently | ||
724 | * in vblank. | ||
725 | * | ||
726 | * Instead let's assume that we're already in vblank if | ||
727 | * we got called from the vblank interrupt and the | ||
728 | * scanline counter value indicates that we're on the | ||
729 | * line just prior to vblank start. This should result | ||
730 | * in the correct answer, unless the vblank interrupt | ||
731 | * delivery really got delayed for almost exactly one | ||
732 | * full frame/field. | ||
733 | */ | ||
734 | if (flags & DRM_CALLED_FROM_VBLIRQ && | ||
735 | position == vbl_start - 1) { | ||
736 | position = (position + 1) % vtotal; | ||
737 | |||
738 | /* Signal this correction as "applied". */ | ||
739 | ret |= 0x8; | ||
740 | } | ||
741 | } | ||
736 | } else { | 742 | } else { |
737 | /* Have access to pixelcount since start of frame. | 743 | /* Have access to pixelcount since start of frame. |
738 | * We can split this into vertical and horizontal | 744 | * We can split this into vertical and horizontal |
@@ -809,7 +815,8 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, | |||
809 | /* Helper routine in DRM core does all the work: */ | 815 | /* Helper routine in DRM core does all the work: */ |
810 | return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error, | 816 | return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error, |
811 | vblank_time, flags, | 817 | vblank_time, flags, |
812 | crtc); | 818 | crtc, |
819 | &to_intel_crtc(crtc)->config.adjusted_mode); | ||
813 | } | 820 | } |
814 | 821 | ||
815 | static bool intel_hpd_irq_event(struct drm_device *dev, | 822 | static bool intel_hpd_irq_event(struct drm_device *dev, |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e77d4b8856a7..14b024becb91 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -9597,21 +9597,19 @@ static int __intel_set_mode(struct drm_crtc *crtc, | |||
9597 | { | 9597 | { |
9598 | struct drm_device *dev = crtc->dev; | 9598 | struct drm_device *dev = crtc->dev; |
9599 | drm_i915_private_t *dev_priv = dev->dev_private; | 9599 | drm_i915_private_t *dev_priv = dev->dev_private; |
9600 | struct drm_display_mode *saved_mode, *saved_hwmode; | 9600 | struct drm_display_mode *saved_mode; |
9601 | struct intel_crtc_config *pipe_config = NULL; | 9601 | struct intel_crtc_config *pipe_config = NULL; |
9602 | struct intel_crtc *intel_crtc; | 9602 | struct intel_crtc *intel_crtc; |
9603 | unsigned disable_pipes, prepare_pipes, modeset_pipes; | 9603 | unsigned disable_pipes, prepare_pipes, modeset_pipes; |
9604 | int ret = 0; | 9604 | int ret = 0; |
9605 | 9605 | ||
9606 | saved_mode = kcalloc(2, sizeof(*saved_mode), GFP_KERNEL); | 9606 | saved_mode = kmalloc(sizeof(*saved_mode), GFP_KERNEL); |
9607 | if (!saved_mode) | 9607 | if (!saved_mode) |
9608 | return -ENOMEM; | 9608 | return -ENOMEM; |
9609 | saved_hwmode = saved_mode + 1; | ||
9610 | 9609 | ||
9611 | intel_modeset_affected_pipes(crtc, &modeset_pipes, | 9610 | intel_modeset_affected_pipes(crtc, &modeset_pipes, |
9612 | &prepare_pipes, &disable_pipes); | 9611 | &prepare_pipes, &disable_pipes); |
9613 | 9612 | ||
9614 | *saved_hwmode = crtc->hwmode; | ||
9615 | *saved_mode = crtc->mode; | 9613 | *saved_mode = crtc->mode; |
9616 | 9614 | ||
9617 | /* Hack: Because we don't (yet) support global modeset on multiple | 9615 | /* Hack: Because we don't (yet) support global modeset on multiple |
@@ -9662,6 +9660,14 @@ static int __intel_set_mode(struct drm_crtc *crtc, | |||
9662 | /* mode_set/enable/disable functions rely on a correct pipe | 9660 | /* mode_set/enable/disable functions rely on a correct pipe |
9663 | * config. */ | 9661 | * config. */ |
9664 | to_intel_crtc(crtc)->config = *pipe_config; | 9662 | to_intel_crtc(crtc)->config = *pipe_config; |
9663 | |||
9664 | /* | ||
9665 | * Calculate and store various constants which | ||
9666 | * are later needed by vblank and swap-completion | ||
9667 | * timestamping. They are derived from true hwmode. | ||
9668 | */ | ||
9669 | drm_calc_timestamping_constants(crtc, | ||
9670 | &pipe_config->adjusted_mode); | ||
9665 | } | 9671 | } |
9666 | 9672 | ||
9667 | /* Only after disabling all output pipelines that will be changed can we | 9673 | /* Only after disabling all output pipelines that will be changed can we |
@@ -9685,23 +9691,10 @@ static int __intel_set_mode(struct drm_crtc *crtc, | |||
9685 | for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) | 9691 | for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) |
9686 | dev_priv->display.crtc_enable(&intel_crtc->base); | 9692 | dev_priv->display.crtc_enable(&intel_crtc->base); |
9687 | 9693 | ||
9688 | if (modeset_pipes) { | ||
9689 | /* Store real post-adjustment hardware mode. */ | ||
9690 | crtc->hwmode = pipe_config->adjusted_mode; | ||
9691 | |||
9692 | /* Calculate and store various constants which | ||
9693 | * are later needed by vblank and swap-completion | ||
9694 | * timestamping. They are derived from true hwmode. | ||
9695 | */ | ||
9696 | drm_calc_timestamping_constants(crtc); | ||
9697 | } | ||
9698 | |||
9699 | /* FIXME: add subpixel order */ | 9694 | /* FIXME: add subpixel order */ |
9700 | done: | 9695 | done: |
9701 | if (ret && crtc->enabled) { | 9696 | if (ret && crtc->enabled) |
9702 | crtc->hwmode = *saved_hwmode; | ||
9703 | crtc->mode = *saved_mode; | 9697 | crtc->mode = *saved_mode; |
9704 | } | ||
9705 | 9698 | ||
9706 | out: | 9699 | out: |
9707 | kfree(pipe_config); | 9700 | kfree(pipe_config); |
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 00bca1bd5745..f48bd6dc10cd 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c | |||
@@ -1799,7 +1799,8 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, | |||
1799 | if (misc & ATOM_DOUBLE_CLOCK_MODE) | 1799 | if (misc & ATOM_DOUBLE_CLOCK_MODE) |
1800 | mode->flags |= DRM_MODE_FLAG_DBLSCAN; | 1800 | mode->flags |= DRM_MODE_FLAG_DBLSCAN; |
1801 | 1801 | ||
1802 | mode->clock = le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10; | 1802 | mode->crtc_clock = mode->clock = |
1803 | le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10; | ||
1803 | 1804 | ||
1804 | if (index == 1) { | 1805 | if (index == 1) { |
1805 | /* PAL timings appear to have wrong values for totals */ | 1806 | /* PAL timings appear to have wrong values for totals */ |
@@ -1842,7 +1843,8 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, | |||
1842 | if (misc & ATOM_DOUBLE_CLOCK_MODE) | 1843 | if (misc & ATOM_DOUBLE_CLOCK_MODE) |
1843 | mode->flags |= DRM_MODE_FLAG_DBLSCAN; | 1844 | mode->flags |= DRM_MODE_FLAG_DBLSCAN; |
1844 | 1845 | ||
1845 | mode->clock = le16_to_cpu(dtd_timings->usPixClk) * 10; | 1846 | mode->crtc_clock = mode->clock = |
1847 | le16_to_cpu(dtd_timings->usPixClk) * 10; | ||
1846 | break; | 1848 | break; |
1847 | } | 1849 | } |
1848 | return true; | 1850 | return true; |
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 7ea647b84733..d680608f6f5b 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c | |||
@@ -306,7 +306,7 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id) | |||
306 | * to complete in this vblank? | 306 | * to complete in this vblank? |
307 | */ | 307 | */ |
308 | if (update_pending && | 308 | if (update_pending && |
309 | (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id, | 309 | (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id, 0, |
310 | &vpos, &hpos, NULL, NULL)) && | 310 | &vpos, &hpos, NULL, NULL)) && |
311 | ((vpos >= (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100) || | 311 | ((vpos >= (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100) || |
312 | (vpos < 0 && !ASIC_IS_AVIVO(rdev)))) { | 312 | (vpos < 0 && !ASIC_IS_AVIVO(rdev)))) { |
@@ -1610,6 +1610,7 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, | |||
1610 | * | 1610 | * |
1611 | * \param dev Device to query. | 1611 | * \param dev Device to query. |
1612 | * \param crtc Crtc to query. | 1612 | * \param crtc Crtc to query. |
1613 | * \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0). | ||
1613 | * \param *vpos Location where vertical scanout position should be stored. | 1614 | * \param *vpos Location where vertical scanout position should be stored. |
1614 | * \param *hpos Location where horizontal scanout position should go. | 1615 | * \param *hpos Location where horizontal scanout position should go. |
1615 | * \param *stime Target location for timestamp taken immediately before | 1616 | * \param *stime Target location for timestamp taken immediately before |
@@ -1631,8 +1632,8 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, | |||
1631 | * unknown small number of scanlines wrt. real scanout position. | 1632 | * unknown small number of scanlines wrt. real scanout position. |
1632 | * | 1633 | * |
1633 | */ | 1634 | */ |
1634 | int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int *hpos, | 1635 | int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int flags, |
1635 | ktime_t *stime, ktime_t *etime) | 1636 | int *vpos, int *hpos, ktime_t *stime, ktime_t *etime) |
1636 | { | 1637 | { |
1637 | u32 stat_crtc = 0, vbl = 0, position = 0; | 1638 | u32 stat_crtc = 0, vbl = 0, position = 0; |
1638 | int vbl_start, vbl_end, vtotal, ret = 0; | 1639 | int vbl_start, vbl_end, vtotal, ret = 0; |
@@ -1774,5 +1775,27 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int | |||
1774 | if (in_vbl) | 1775 | if (in_vbl) |
1775 | ret |= DRM_SCANOUTPOS_INVBL; | 1776 | ret |= DRM_SCANOUTPOS_INVBL; |
1776 | 1777 | ||
1778 | /* Is vpos outside nominal vblank area, but less than | ||
1779 | * 1/100 of a frame height away from start of vblank? | ||
1780 | * If so, assume this isn't a massively delayed vblank | ||
1781 | * interrupt, but a vblank interrupt that fired a few | ||
1782 | * microseconds before true start of vblank. Compensate | ||
1783 | * by adding a full frame duration to the final timestamp. | ||
1784 | * Happens, e.g., on ATI R500, R600. | ||
1785 | * | ||
1786 | * We only do this if DRM_CALLED_FROM_VBLIRQ. | ||
1787 | */ | ||
1788 | if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) { | ||
1789 | vbl_start = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vdisplay; | ||
1790 | vtotal = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vtotal; | ||
1791 | |||
1792 | if (vbl_start - *vpos < vtotal / 100) { | ||
1793 | *vpos -= vtotal; | ||
1794 | |||
1795 | /* Signal this correction as "applied". */ | ||
1796 | ret |= 0x8; | ||
1797 | } | ||
1798 | } | ||
1799 | |||
1777 | return ret; | 1800 | return ret; |
1778 | } | 1801 | } |
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 67fadcf4590f..1235a78fbba1 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c | |||
@@ -109,6 +109,7 @@ int radeon_gem_object_open(struct drm_gem_object *obj, | |||
109 | void radeon_gem_object_close(struct drm_gem_object *obj, | 109 | void radeon_gem_object_close(struct drm_gem_object *obj, |
110 | struct drm_file *file_priv); | 110 | struct drm_file *file_priv); |
111 | extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, | 111 | extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, |
112 | unsigned int flags, | ||
112 | int *vpos, int *hpos, ktime_t *stime, | 113 | int *vpos, int *hpos, ktime_t *stime, |
113 | ktime_t *etime); | 114 | ktime_t *etime); |
114 | extern const struct drm_ioctl_desc radeon_ioctls_kms[]; | 115 | extern const struct drm_ioctl_desc radeon_ioctls_kms[]; |
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 9e3af24e1b05..114d1672d616 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c | |||
@@ -719,7 +719,7 @@ int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc, | |||
719 | /* Helper routine in DRM core does all the work: */ | 719 | /* Helper routine in DRM core does all the work: */ |
720 | return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error, | 720 | return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error, |
721 | vblank_time, flags, | 721 | vblank_time, flags, |
722 | drmcrtc); | 722 | drmcrtc, &drmcrtc->hwmode); |
723 | } | 723 | } |
724 | 724 | ||
725 | #define KMS_INVALID_IOCTL(name) \ | 725 | #define KMS_INVALID_IOCTL(name) \ |
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 7c53fb1cc46d..402dbe32c234 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h | |||
@@ -801,6 +801,7 @@ extern int radeon_crtc_cursor_move(struct drm_crtc *crtc, | |||
801 | int x, int y); | 801 | int x, int y); |
802 | 802 | ||
803 | extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, | 803 | extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, |
804 | unsigned int flags, | ||
804 | int *vpos, int *hpos, ktime_t *stime, | 805 | int *vpos, int *hpos, ktime_t *stime, |
805 | ktime_t *etime); | 806 | ktime_t *etime); |
806 | 807 | ||
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 4e7f8922ae62..8e8153e471c2 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c | |||
@@ -1486,7 +1486,7 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev) | |||
1486 | */ | 1486 | */ |
1487 | for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) { | 1487 | for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) { |
1488 | if (rdev->pm.active_crtcs & (1 << crtc)) { | 1488 | if (rdev->pm.active_crtcs & (1 << crtc)) { |
1489 | vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, &vpos, &hpos, NULL, NULL); | 1489 | vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0, &vpos, &hpos, NULL, NULL); |
1490 | if ((vbl_status & DRM_SCANOUTPOS_VALID) && | 1490 | if ((vbl_status & DRM_SCANOUTPOS_VALID) && |
1491 | !(vbl_status & DRM_SCANOUTPOS_INVBL)) | 1491 | !(vbl_status & DRM_SCANOUTPOS_INVBL)) |
1492 | in_vbl = false; | 1492 | in_vbl = false; |
diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 63eab2b72ee7..04086c5be930 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h | |||
@@ -845,6 +845,7 @@ struct drm_driver { | |||
845 | * | 845 | * |
846 | * \param dev DRM device. | 846 | * \param dev DRM device. |
847 | * \param crtc Id of the crtc to query. | 847 | * \param crtc Id of the crtc to query. |
848 | * \param flags Flags from the caller (DRM_CALLED_FROM_VBLIRQ or 0). | ||
848 | * \param *vpos Target location for current vertical scanout position. | 849 | * \param *vpos Target location for current vertical scanout position. |
849 | * \param *hpos Target location for current horizontal scanout position. | 850 | * \param *hpos Target location for current horizontal scanout position. |
850 | * \param *stime Target location for timestamp taken immediately before | 851 | * \param *stime Target location for timestamp taken immediately before |
@@ -867,6 +868,7 @@ struct drm_driver { | |||
867 | * | 868 | * |
868 | */ | 869 | */ |
869 | int (*get_scanout_position) (struct drm_device *dev, int crtc, | 870 | int (*get_scanout_position) (struct drm_device *dev, int crtc, |
871 | unsigned int flags, | ||
870 | int *vpos, int *hpos, ktime_t *stime, | 872 | int *vpos, int *hpos, ktime_t *stime, |
871 | ktime_t *etime); | 873 | ktime_t *etime); |
872 | 874 | ||
@@ -1401,8 +1403,10 @@ extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, | |||
1401 | int crtc, int *max_error, | 1403 | int crtc, int *max_error, |
1402 | struct timeval *vblank_time, | 1404 | struct timeval *vblank_time, |
1403 | unsigned flags, | 1405 | unsigned flags, |
1404 | struct drm_crtc *refcrtc); | 1406 | const struct drm_crtc *refcrtc, |
1405 | extern void drm_calc_timestamping_constants(struct drm_crtc *crtc); | 1407 | const struct drm_display_mode *mode); |
1408 | extern void drm_calc_timestamping_constants(struct drm_crtc *crtc, | ||
1409 | const struct drm_display_mode *mode); | ||
1406 | 1410 | ||
1407 | extern bool | 1411 | extern bool |
1408 | drm_mode_parse_command_line_for_connector(const char *mode_option, | 1412 | drm_mode_parse_command_line_for_connector(const char *mode_option, |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index e51e8975dd6f..e963470efd39 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -449,7 +449,7 @@ struct drm_crtc { | |||
449 | uint16_t *gamma_store; | 449 | uint16_t *gamma_store; |
450 | 450 | ||
451 | /* Constants needed for precise vblank and swap timestamping. */ | 451 | /* Constants needed for precise vblank and swap timestamping. */ |
452 | s64 framedur_ns, linedur_ns, pixeldur_ns; | 452 | int framedur_ns, linedur_ns, pixeldur_ns; |
453 | 453 | ||
454 | /* if you are using the helper */ | 454 | /* if you are using the helper */ |
455 | void *helper_private; | 455 | void *helper_private; |