diff options
Diffstat (limited to 'drivers/gpu/drm/drm_irq.c')
-rw-r--r-- | drivers/gpu/drm/drm_irq.c | 129 |
1 files changed, 72 insertions, 57 deletions
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 8c866cac62dd..c7debaad67f8 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c | |||
@@ -54,7 +54,7 @@ | |||
54 | 54 | ||
55 | static bool | 55 | static bool |
56 | drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe, | 56 | drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe, |
57 | struct timeval *tvblank, unsigned flags); | 57 | struct timeval *tvblank, bool in_vblank_irq); |
58 | 58 | ||
59 | static unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ | 59 | static unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ |
60 | 60 | ||
@@ -138,7 +138,7 @@ static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe | |||
138 | */ | 138 | */ |
139 | do { | 139 | do { |
140 | cur_vblank = __get_vblank_counter(dev, pipe); | 140 | cur_vblank = __get_vblank_counter(dev, pipe); |
141 | rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, 0); | 141 | rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, false); |
142 | } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); | 142 | } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); |
143 | 143 | ||
144 | /* | 144 | /* |
@@ -171,7 +171,7 @@ static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe | |||
171 | * device vblank fields. | 171 | * device vblank fields. |
172 | */ | 172 | */ |
173 | static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, | 173 | static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, |
174 | unsigned long flags) | 174 | bool in_vblank_irq) |
175 | { | 175 | { |
176 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; | 176 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
177 | u32 cur_vblank, diff; | 177 | u32 cur_vblank, diff; |
@@ -194,7 +194,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, | |||
194 | */ | 194 | */ |
195 | do { | 195 | do { |
196 | cur_vblank = __get_vblank_counter(dev, pipe); | 196 | cur_vblank = __get_vblank_counter(dev, pipe); |
197 | rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, flags); | 197 | rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq); |
198 | } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); | 198 | } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); |
199 | 199 | ||
200 | if (dev->max_vblank_count != 0) { | 200 | if (dev->max_vblank_count != 0) { |
@@ -214,13 +214,13 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, | |||
214 | */ | 214 | */ |
215 | diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns); | 215 | diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns); |
216 | 216 | ||
217 | if (diff == 0 && flags & DRM_CALLED_FROM_VBLIRQ) | 217 | if (diff == 0 && in_vblank_irq) |
218 | DRM_DEBUG_VBL("crtc %u: Redundant vblirq ignored." | 218 | DRM_DEBUG_VBL("crtc %u: Redundant vblirq ignored." |
219 | " diff_ns = %lld, framedur_ns = %d)\n", | 219 | " diff_ns = %lld, framedur_ns = %d)\n", |
220 | pipe, (long long) diff_ns, framedur_ns); | 220 | pipe, (long long) diff_ns, framedur_ns); |
221 | } else { | 221 | } else { |
222 | /* some kind of default for drivers w/o accurate vbl timestamping */ | 222 | /* some kind of default for drivers w/o accurate vbl timestamping */ |
223 | diff = (flags & DRM_CALLED_FROM_VBLIRQ) != 0; | 223 | diff = in_vblank_irq ? 1 : 0; |
224 | } | 224 | } |
225 | 225 | ||
226 | /* | 226 | /* |
@@ -253,7 +253,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, | |||
253 | * Otherwise reinitialize delayed at next vblank interrupt and assign 0 | 253 | * Otherwise reinitialize delayed at next vblank interrupt and assign 0 |
254 | * for now, to mark the vblanktimestamp as invalid. | 254 | * for now, to mark the vblanktimestamp as invalid. |
255 | */ | 255 | */ |
256 | if (!rc && (flags & DRM_CALLED_FROM_VBLIRQ) == 0) | 256 | if (!rc && in_vblank_irq) |
257 | t_vblank = (struct timeval) {0, 0}; | 257 | t_vblank = (struct timeval) {0, 0}; |
258 | 258 | ||
259 | store_vblank(dev, pipe, diff, &t_vblank, cur_vblank); | 259 | store_vblank(dev, pipe, diff, &t_vblank, cur_vblank); |
@@ -291,7 +291,7 @@ u32 drm_accurate_vblank_count(struct drm_crtc *crtc) | |||
291 | 291 | ||
292 | spin_lock_irqsave(&dev->vblank_time_lock, flags); | 292 | spin_lock_irqsave(&dev->vblank_time_lock, flags); |
293 | 293 | ||
294 | drm_update_vblank_count(dev, pipe, 0); | 294 | drm_update_vblank_count(dev, pipe, false); |
295 | vblank = drm_vblank_count(dev, pipe); | 295 | vblank = drm_vblank_count(dev, pipe); |
296 | 296 | ||
297 | spin_unlock_irqrestore(&dev->vblank_time_lock, flags); | 297 | spin_unlock_irqrestore(&dev->vblank_time_lock, flags); |
@@ -349,7 +349,7 @@ static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe) | |||
349 | * this time. This makes the count account for the entire time | 349 | * this time. This makes the count account for the entire time |
350 | * between drm_crtc_vblank_on() and drm_crtc_vblank_off(). | 350 | * between drm_crtc_vblank_on() and drm_crtc_vblank_off(). |
351 | */ | 351 | */ |
352 | drm_update_vblank_count(dev, pipe, 0); | 352 | drm_update_vblank_count(dev, pipe, false); |
353 | 353 | ||
354 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); | 354 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); |
355 | } | 355 | } |
@@ -684,6 +684,7 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc, | |||
684 | 684 | ||
685 | vblank->linedur_ns = linedur_ns; | 685 | vblank->linedur_ns = linedur_ns; |
686 | vblank->framedur_ns = framedur_ns; | 686 | vblank->framedur_ns = framedur_ns; |
687 | vblank->hwmode = *mode; | ||
687 | 688 | ||
688 | DRM_DEBUG("crtc %u: hwmode: htotal %d, vtotal %d, vdisplay %d\n", | 689 | DRM_DEBUG("crtc %u: hwmode: htotal %d, vtotal %d, vdisplay %d\n", |
689 | crtc->base.id, mode->crtc_htotal, | 690 | crtc->base.id, mode->crtc_htotal, |
@@ -700,10 +701,10 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants); | |||
700 | * @max_error: Desired maximum allowable error in timestamps (nanosecs) | 701 | * @max_error: Desired maximum allowable error in timestamps (nanosecs) |
701 | * On return contains true maximum error of timestamp | 702 | * On return contains true maximum error of timestamp |
702 | * @vblank_time: Pointer to struct timeval which should receive the timestamp | 703 | * @vblank_time: Pointer to struct timeval which should receive the timestamp |
703 | * @flags: Flags to pass to driver: | 704 | * @in_vblank_irq: |
704 | * 0 = Default, | 705 | * True when called from drm_crtc_handle_vblank(). Some drivers |
705 | * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl IRQ handler | 706 | * need to apply some workarounds for gpu-specific vblank irq quirks |
706 | * @mode: mode which defines the scanout timings | 707 | * if flag is set. |
707 | * | 708 | * |
708 | * Implements calculation of exact vblank timestamps from given drm_display_mode | 709 | * Implements calculation of exact vblank timestamps from given drm_display_mode |
709 | * timings and current video scanout position of a CRTC. This can be called from | 710 | * timings and current video scanout position of a CRTC. This can be called from |
@@ -723,52 +724,62 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants); | |||
723 | * returns as no operation if a doublescan or interlaced video mode is | 724 | * returns as no operation if a doublescan or interlaced video mode is |
724 | * active. Higher level code is expected to handle this. | 725 | * active. Higher level code is expected to handle this. |
725 | * | 726 | * |
726 | * Returns: | 727 | * This function can be used to implement the &drm_driver.get_vblank_timestamp |
727 | * Negative value on error, failure or if not supported in current | 728 | * directly, if the driver implements the &drm_driver.get_scanout_position hook. |
728 | * video mode: | ||
729 | * | ||
730 | * -EINVAL Invalid CRTC. | ||
731 | * -EAGAIN Temporary unavailable, e.g., called before initial modeset. | ||
732 | * -ENOTSUPP Function not supported in current display mode. | ||
733 | * -EIO Failed, e.g., due to failed scanout position query. | ||
734 | * | 729 | * |
735 | * Returns or'ed positive status flags on success: | 730 | * Note that atomic drivers must call drm_calc_timestamping_constants() before |
731 | * enabling a CRTC. The atomic helpers already take care of that in | ||
732 | * drm_atomic_helper_update_legacy_modeset_state(). | ||
736 | * | 733 | * |
737 | * DRM_VBLANKTIME_SCANOUTPOS_METHOD - Signal this method used for timestamping. | 734 | * Returns: |
738 | * DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval. | ||
739 | * | 735 | * |
736 | * Returns true on success, and false on failure, i.e. when no accurate | ||
737 | * timestamp could be acquired. | ||
740 | */ | 738 | */ |
741 | int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, | 739 | bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, |
742 | unsigned int pipe, | 740 | unsigned int pipe, |
743 | int *max_error, | 741 | int *max_error, |
744 | struct timeval *vblank_time, | 742 | struct timeval *vblank_time, |
745 | unsigned flags, | 743 | bool in_vblank_irq) |
746 | const struct drm_display_mode *mode) | ||
747 | { | 744 | { |
748 | struct timeval tv_etime; | 745 | struct timeval tv_etime; |
749 | ktime_t stime, etime; | 746 | ktime_t stime, etime; |
750 | unsigned int vbl_status; | 747 | bool vbl_status; |
751 | int ret = DRM_VBLANKTIME_SCANOUTPOS_METHOD; | 748 | struct drm_crtc *crtc; |
749 | const struct drm_display_mode *mode; | ||
750 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; | ||
752 | int vpos, hpos, i; | 751 | int vpos, hpos, i; |
753 | int delta_ns, duration_ns; | 752 | int delta_ns, duration_ns; |
754 | 753 | ||
755 | if (pipe >= dev->num_crtcs) { | 754 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
755 | return false; | ||
756 | |||
757 | crtc = drm_crtc_from_index(dev, pipe); | ||
758 | |||
759 | if (pipe >= dev->num_crtcs || !crtc) { | ||
756 | DRM_ERROR("Invalid crtc %u\n", pipe); | 760 | DRM_ERROR("Invalid crtc %u\n", pipe); |
757 | return -EINVAL; | 761 | return false; |
758 | } | 762 | } |
759 | 763 | ||
760 | /* Scanout position query not supported? Should not happen. */ | 764 | /* Scanout position query not supported? Should not happen. */ |
761 | if (!dev->driver->get_scanout_position) { | 765 | if (!dev->driver->get_scanout_position) { |
762 | DRM_ERROR("Called from driver w/o get_scanout_position()!?\n"); | 766 | DRM_ERROR("Called from driver w/o get_scanout_position()!?\n"); |
763 | return -EIO; | 767 | return false; |
764 | } | 768 | } |
765 | 769 | ||
770 | if (drm_drv_uses_atomic_modeset(dev)) | ||
771 | mode = &vblank->hwmode; | ||
772 | else | ||
773 | mode = &crtc->hwmode; | ||
774 | |||
766 | /* If mode timing undefined, just return as no-op: | 775 | /* If mode timing undefined, just return as no-op: |
767 | * Happens during initial modesetting of a crtc. | 776 | * Happens during initial modesetting of a crtc. |
768 | */ | 777 | */ |
769 | if (mode->crtc_clock == 0) { | 778 | if (mode->crtc_clock == 0) { |
770 | DRM_DEBUG("crtc %u: Noop due to uninitialized mode.\n", pipe); | 779 | DRM_DEBUG("crtc %u: Noop due to uninitialized mode.\n", pipe); |
771 | return -EAGAIN; | 780 | WARN_ON_ONCE(drm_drv_uses_atomic_modeset(dev)); |
781 | |||
782 | return false; | ||
772 | } | 783 | } |
773 | 784 | ||
774 | /* Get current scanout position with system timestamp. | 785 | /* Get current scanout position with system timestamp. |
@@ -783,16 +794,17 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, | |||
783 | * Get vertical and horizontal scanout position vpos, hpos, | 794 | * Get vertical and horizontal scanout position vpos, hpos, |
784 | * and bounding timestamps stime, etime, pre/post query. | 795 | * and bounding timestamps stime, etime, pre/post query. |
785 | */ | 796 | */ |
786 | vbl_status = dev->driver->get_scanout_position(dev, pipe, flags, | 797 | vbl_status = dev->driver->get_scanout_position(dev, pipe, |
798 | in_vblank_irq, | ||
787 | &vpos, &hpos, | 799 | &vpos, &hpos, |
788 | &stime, &etime, | 800 | &stime, &etime, |
789 | mode); | 801 | mode); |
790 | 802 | ||
791 | /* Return as no-op if scanout query unsupported or failed. */ | 803 | /* Return as no-op if scanout query unsupported or failed. */ |
792 | if (!(vbl_status & DRM_SCANOUTPOS_VALID)) { | 804 | if (!vbl_status) { |
793 | DRM_DEBUG("crtc %u : scanoutpos query failed [0x%x].\n", | 805 | DRM_DEBUG("crtc %u : scanoutpos query failed.\n", |
794 | pipe, vbl_status); | 806 | pipe); |
795 | return -EIO; | 807 | return false; |
796 | } | 808 | } |
797 | 809 | ||
798 | /* Compute uncertainty in timestamp of scanout position query. */ | 810 | /* Compute uncertainty in timestamp of scanout position query. */ |
@@ -830,13 +842,13 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, | |||
830 | etime = ktime_sub_ns(etime, delta_ns); | 842 | etime = ktime_sub_ns(etime, delta_ns); |
831 | *vblank_time = ktime_to_timeval(etime); | 843 | *vblank_time = ktime_to_timeval(etime); |
832 | 844 | ||
833 | DRM_DEBUG_VBL("crtc %u : v 0x%x p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n", | 845 | DRM_DEBUG_VBL("crtc %u : v p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n", |
834 | pipe, vbl_status, hpos, vpos, | 846 | pipe, hpos, vpos, |
835 | (long)tv_etime.tv_sec, (long)tv_etime.tv_usec, | 847 | (long)tv_etime.tv_sec, (long)tv_etime.tv_usec, |
836 | (long)vblank_time->tv_sec, (long)vblank_time->tv_usec, | 848 | (long)vblank_time->tv_sec, (long)vblank_time->tv_usec, |
837 | duration_ns/1000, i); | 849 | duration_ns/1000, i); |
838 | 850 | ||
839 | return ret; | 851 | return true; |
840 | } | 852 | } |
841 | EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos); | 853 | EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos); |
842 | 854 | ||
@@ -854,9 +866,10 @@ static struct timeval get_drm_timestamp(void) | |||
854 | * @dev: DRM device | 866 | * @dev: DRM device |
855 | * @pipe: index of CRTC whose vblank timestamp to retrieve | 867 | * @pipe: index of CRTC whose vblank timestamp to retrieve |
856 | * @tvblank: Pointer to target struct timeval which should receive the timestamp | 868 | * @tvblank: Pointer to target struct timeval which should receive the timestamp |
857 | * @flags: Flags to pass to driver: | 869 | * @in_vblank_irq: |
858 | * 0 = Default, | 870 | * True when called from drm_crtc_handle_vblank(). Some drivers |
859 | * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl IRQ handler | 871 | * need to apply some workarounds for gpu-specific vblank irq quirks |
872 | * if flag is set. | ||
860 | * | 873 | * |
861 | * Fetches the system timestamp corresponding to the time of the most recent | 874 | * Fetches the system timestamp corresponding to the time of the most recent |
862 | * vblank interval on specified CRTC. May call into kms-driver to | 875 | * vblank interval on specified CRTC. May call into kms-driver to |
@@ -870,27 +883,25 @@ static struct timeval get_drm_timestamp(void) | |||
870 | */ | 883 | */ |
871 | static bool | 884 | static bool |
872 | drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe, | 885 | drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe, |
873 | struct timeval *tvblank, unsigned flags) | 886 | struct timeval *tvblank, bool in_vblank_irq) |
874 | { | 887 | { |
875 | int ret; | 888 | bool ret = false; |
876 | 889 | ||
877 | /* Define requested maximum error on timestamps (nanoseconds). */ | 890 | /* Define requested maximum error on timestamps (nanoseconds). */ |
878 | int max_error = (int) drm_timestamp_precision * 1000; | 891 | int max_error = (int) drm_timestamp_precision * 1000; |
879 | 892 | ||
880 | /* Query driver if possible and precision timestamping enabled. */ | 893 | /* Query driver if possible and precision timestamping enabled. */ |
881 | if (dev->driver->get_vblank_timestamp && (max_error > 0)) { | 894 | if (dev->driver->get_vblank_timestamp && (max_error > 0)) |
882 | ret = dev->driver->get_vblank_timestamp(dev, pipe, &max_error, | 895 | ret = dev->driver->get_vblank_timestamp(dev, pipe, &max_error, |
883 | tvblank, flags); | 896 | tvblank, in_vblank_irq); |
884 | if (ret > 0) | ||
885 | return true; | ||
886 | } | ||
887 | 897 | ||
888 | /* GPU high precision timestamp query unsupported or failed. | 898 | /* GPU high precision timestamp query unsupported or failed. |
889 | * Return current monotonic/gettimeofday timestamp as best estimate. | 899 | * Return current monotonic/gettimeofday timestamp as best estimate. |
890 | */ | 900 | */ |
891 | *tvblank = get_drm_timestamp(); | 901 | if (!ret) |
902 | *tvblank = get_drm_timestamp(); | ||
892 | 903 | ||
893 | return false; | 904 | return ret; |
894 | } | 905 | } |
895 | 906 | ||
896 | /** | 907 | /** |
@@ -1329,6 +1340,10 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc) | |||
1329 | send_vblank_event(dev, e, seq, &now); | 1340 | send_vblank_event(dev, e, seq, &now); |
1330 | } | 1341 | } |
1331 | spin_unlock_irqrestore(&dev->event_lock, irqflags); | 1342 | spin_unlock_irqrestore(&dev->event_lock, irqflags); |
1343 | |||
1344 | /* Will be reset by the modeset helpers when re-enabling the crtc by | ||
1345 | * calling drm_calc_timestamping_constants(). */ | ||
1346 | vblank->hwmode.crtc_clock = 0; | ||
1332 | } | 1347 | } |
1333 | EXPORT_SYMBOL(drm_crtc_vblank_off); | 1348 | EXPORT_SYMBOL(drm_crtc_vblank_off); |
1334 | 1349 | ||
@@ -1760,7 +1775,7 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe) | |||
1760 | return false; | 1775 | return false; |
1761 | } | 1776 | } |
1762 | 1777 | ||
1763 | drm_update_vblank_count(dev, pipe, DRM_CALLED_FROM_VBLIRQ); | 1778 | drm_update_vblank_count(dev, pipe, true); |
1764 | 1779 | ||
1765 | spin_unlock(&dev->vblank_time_lock); | 1780 | spin_unlock(&dev->vblank_time_lock); |
1766 | 1781 | ||