diff options
Diffstat (limited to 'drivers/gpu/drm/drm_atomic_helper.c')
-rw-r--r-- | drivers/gpu/drm/drm_atomic_helper.c | 112 |
1 files changed, 103 insertions, 9 deletions
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index b16f1d69a0bb..ab4032167094 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c | |||
@@ -696,6 +696,100 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, | |||
696 | EXPORT_SYMBOL(drm_atomic_helper_check_modeset); | 696 | EXPORT_SYMBOL(drm_atomic_helper_check_modeset); |
697 | 697 | ||
698 | /** | 698 | /** |
699 | * drm_atomic_helper_check_plane_state() - Check plane state for validity | ||
700 | * @plane_state: plane state to check | ||
701 | * @crtc_state: crtc state to check | ||
702 | * @clip: integer clipping coordinates | ||
703 | * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point | ||
704 | * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point | ||
705 | * @can_position: is it legal to position the plane such that it | ||
706 | * doesn't cover the entire crtc? This will generally | ||
707 | * only be false for primary planes. | ||
708 | * @can_update_disabled: can the plane be updated while the crtc | ||
709 | * is disabled? | ||
710 | * | ||
711 | * Checks that a desired plane update is valid, and updates various | ||
712 | * bits of derived state (clipped coordinates etc.). Drivers that provide | ||
713 | * their own plane handling rather than helper-provided implementations may | ||
714 | * still wish to call this function to avoid duplication of error checking | ||
715 | * code. | ||
716 | * | ||
717 | * RETURNS: | ||
718 | * Zero if update appears valid, error code on failure | ||
719 | */ | ||
720 | int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, | ||
721 | const struct drm_crtc_state *crtc_state, | ||
722 | const struct drm_rect *clip, | ||
723 | int min_scale, | ||
724 | int max_scale, | ||
725 | bool can_position, | ||
726 | bool can_update_disabled) | ||
727 | { | ||
728 | struct drm_framebuffer *fb = plane_state->fb; | ||
729 | struct drm_rect *src = &plane_state->src; | ||
730 | struct drm_rect *dst = &plane_state->dst; | ||
731 | unsigned int rotation = plane_state->rotation; | ||
732 | int hscale, vscale; | ||
733 | |||
734 | WARN_ON(plane_state->crtc && plane_state->crtc != crtc_state->crtc); | ||
735 | |||
736 | *src = drm_plane_state_src(plane_state); | ||
737 | *dst = drm_plane_state_dest(plane_state); | ||
738 | |||
739 | if (!fb) { | ||
740 | plane_state->visible = false; | ||
741 | return 0; | ||
742 | } | ||
743 | |||
744 | /* crtc should only be NULL when disabling (i.e., !fb) */ | ||
745 | if (WARN_ON(!plane_state->crtc)) { | ||
746 | plane_state->visible = false; | ||
747 | return 0; | ||
748 | } | ||
749 | |||
750 | if (!crtc_state->enable && !can_update_disabled) { | ||
751 | DRM_DEBUG_KMS("Cannot update plane of a disabled CRTC.\n"); | ||
752 | return -EINVAL; | ||
753 | } | ||
754 | |||
755 | drm_rect_rotate(src, fb->width << 16, fb->height << 16, rotation); | ||
756 | |||
757 | /* Check scaling */ | ||
758 | hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale); | ||
759 | vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale); | ||
760 | if (hscale < 0 || vscale < 0) { | ||
761 | DRM_DEBUG_KMS("Invalid scaling of plane\n"); | ||
762 | drm_rect_debug_print("src: ", &plane_state->src, true); | ||
763 | drm_rect_debug_print("dst: ", &plane_state->dst, false); | ||
764 | return -ERANGE; | ||
765 | } | ||
766 | |||
767 | plane_state->visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale); | ||
768 | |||
769 | drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation); | ||
770 | |||
771 | if (!plane_state->visible) | ||
772 | /* | ||
773 | * Plane isn't visible; some drivers can handle this | ||
774 | * so we just return success here. Drivers that can't | ||
775 | * (including those that use the primary plane helper's | ||
776 | * update function) will return an error from their | ||
777 | * update_plane handler. | ||
778 | */ | ||
779 | return 0; | ||
780 | |||
781 | if (!can_position && !drm_rect_equals(dst, clip)) { | ||
782 | DRM_DEBUG_KMS("Plane must cover entire CRTC\n"); | ||
783 | drm_rect_debug_print("dst: ", dst, false); | ||
784 | drm_rect_debug_print("clip: ", clip, false); | ||
785 | return -EINVAL; | ||
786 | } | ||
787 | |||
788 | return 0; | ||
789 | } | ||
790 | EXPORT_SYMBOL(drm_atomic_helper_check_plane_state); | ||
791 | |||
792 | /** | ||
699 | * drm_atomic_helper_check_planes - validate state object for planes changes | 793 | * drm_atomic_helper_check_planes - validate state object for planes changes |
700 | * @dev: DRM device | 794 | * @dev: DRM device |
701 | * @state: the driver state object | 795 | * @state: the driver state object |
@@ -907,6 +1001,12 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) | |||
907 | * | 1001 | * |
908 | * Drivers can use this for building their own atomic commit if they don't have | 1002 | * Drivers can use this for building their own atomic commit if they don't have |
909 | * a pure helper-based modeset implementation. | 1003 | * a pure helper-based modeset implementation. |
1004 | * | ||
1005 | * Since these updates are not synchronized with lockings, only code paths | ||
1006 | * called from &drm_mode_config_helper_funcs.atomic_commit_tail can look at the | ||
1007 | * legacy state filled out by this helper. Defacto this means this helper and | ||
1008 | * the legacy state pointers are only really useful for transitioning an | ||
1009 | * existing driver to the atomic world. | ||
910 | */ | 1010 | */ |
911 | void | 1011 | void |
912 | drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev, | 1012 | drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev, |
@@ -1787,11 +1887,8 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, | |||
1787 | !try_wait_for_completion(&old_conn_state->commit->flip_done)) | 1887 | !try_wait_for_completion(&old_conn_state->commit->flip_done)) |
1788 | return -EBUSY; | 1888 | return -EBUSY; |
1789 | 1889 | ||
1790 | /* commit tracked through new_crtc_state->commit, no need to do it explicitly */ | 1890 | /* Always track connectors explicitly for e.g. link retraining. */ |
1791 | if (new_conn_state->crtc) | 1891 | commit = crtc_or_fake_commit(state, new_conn_state->crtc ?: old_conn_state->crtc); |
1792 | continue; | ||
1793 | |||
1794 | commit = crtc_or_fake_commit(state, old_conn_state->crtc); | ||
1795 | if (!commit) | 1892 | if (!commit) |
1796 | return -ENOMEM; | 1893 | return -ENOMEM; |
1797 | 1894 | ||
@@ -1805,10 +1902,7 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, | |||
1805 | !try_wait_for_completion(&old_plane_state->commit->flip_done)) | 1902 | !try_wait_for_completion(&old_plane_state->commit->flip_done)) |
1806 | return -EBUSY; | 1903 | return -EBUSY; |
1807 | 1904 | ||
1808 | /* | 1905 | /* Always track planes explicitly for async pageflip support. */ |
1809 | * Unlike connectors, always track planes explicitly for | ||
1810 | * async pageflip support. | ||
1811 | */ | ||
1812 | commit = crtc_or_fake_commit(state, new_plane_state->crtc ?: old_plane_state->crtc); | 1906 | commit = crtc_or_fake_commit(state, new_plane_state->crtc ?: old_plane_state->crtc); |
1813 | if (!commit) | 1907 | if (!commit) |
1814 | return -ENOMEM; | 1908 | return -ENOMEM; |