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 | ||
