Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/atomic: Loosen FB atomic checks

Loosen the requirements for atomic and legacy commit so that, in cases
where pixel_source != FB, the commit can still go through.

This includes adding framebuffer NULL checks in other areas to account for
FB being NULL when non-FB pixel sources are enabled.

To disable a plane, the pixel_source must be NONE or the FB must be NULL
if pixel_source == FB.

Signed-off-by: Jessica Zhang <quic_jesszhan@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20231027-solid-fill-v7-7-780188bfa7b2@quicinc.com

authored by

Jessica Zhang and committed by
Dmitry Baryshkov
f1e75da5 4ba6b7a6

+66 -31
+11 -10
drivers/gpu/drm/drm_atomic.c
··· 674 674 { 675 675 struct drm_plane *plane = new_plane_state->plane; 676 676 struct drm_crtc *crtc = new_plane_state->crtc; 677 - const struct drm_framebuffer *fb = new_plane_state->fb; 678 677 int ret; 679 678 680 - /* either *both* CRTC and FB must be set, or neither */ 681 - if (crtc && !fb) { 682 - drm_dbg_atomic(plane->dev, "[PLANE:%d:%s] CRTC set but no FB\n", 679 + /* either *both* CRTC and pixel source must be set, or neither */ 680 + if (crtc && !drm_plane_has_visible_data(new_plane_state)) { 681 + drm_dbg_atomic(plane->dev, "[PLANE:%d:%s] CRTC set but no visible data\n", 683 682 plane->base.id, plane->name); 684 683 return -EINVAL; 685 - } else if (fb && !crtc) { 686 - drm_dbg_atomic(plane->dev, "[PLANE:%d:%s] FB set but no CRTC\n", 687 - plane->base.id, plane->name); 684 + } else if (drm_plane_has_visible_data(new_plane_state) && !crtc) { 685 + drm_dbg_atomic(plane->dev, "[PLANE:%d:%s] Source %d has visible data but no CRTC\n", 686 + plane->base.id, plane->name, new_plane_state->pixel_source); 688 687 return -EINVAL; 689 688 } 690 689 ··· 714 715 } 715 716 716 717 717 - ret = drm_atomic_plane_check_fb(new_plane_state); 718 - if (ret) 719 - return ret; 718 + if (new_plane_state->pixel_source == DRM_PLANE_PIXEL_SOURCE_FB && new_plane_state->fb) { 719 + ret = drm_atomic_plane_check_fb(new_plane_state); 720 + if (ret) 721 + return ret; 722 + } 720 723 721 724 if (plane_switching_crtc(old_plane_state, new_plane_state)) { 722 725 drm_dbg_atomic(plane->dev,
+24 -19
drivers/gpu/drm/drm_atomic_helper.c
··· 861 861 bool can_position, 862 862 bool can_update_disabled) 863 863 { 864 - struct drm_framebuffer *fb = plane_state->fb; 865 864 struct drm_rect *src = &plane_state->src; 866 865 struct drm_rect *dst = &plane_state->dst; 867 866 unsigned int rotation = plane_state->rotation; ··· 872 873 *src = drm_plane_state_src(plane_state); 873 874 *dst = drm_plane_state_dest(plane_state); 874 875 875 - if (!fb) { 876 + if (!drm_plane_has_visible_data(plane_state)) { 876 877 plane_state->visible = false; 877 878 return 0; 878 879 } ··· 889 890 return -EINVAL; 890 891 } 891 892 892 - drm_rect_rotate(src, fb->width << 16, fb->height << 16, rotation); 893 + /* Check that selected pixel source is valid */ 894 + if (plane_state->pixel_source == DRM_PLANE_PIXEL_SOURCE_FB && plane_state->fb) { 895 + struct drm_framebuffer *fb = plane_state->fb; 896 + drm_rect_rotate(src, fb->width << 16, fb->height << 16, rotation); 893 897 894 - /* Check scaling */ 895 - hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale); 896 - vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale); 897 - if (hscale < 0 || vscale < 0) { 898 - drm_dbg_kms(plane_state->plane->dev, 899 - "Invalid scaling of plane\n"); 900 - drm_rect_debug_print("src: ", &plane_state->src, true); 901 - drm_rect_debug_print("dst: ", &plane_state->dst, false); 902 - return -ERANGE; 898 + /* Check scaling */ 899 + hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale); 900 + vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale); 901 + 902 + if (hscale < 0 || vscale < 0) { 903 + drm_dbg_kms(plane_state->plane->dev, 904 + "Invalid scaling of plane\n"); 905 + drm_rect_debug_print("src: ", &plane_state->src, true); 906 + drm_rect_debug_print("dst: ", &plane_state->dst, false); 907 + return -ERANGE; 908 + } 909 + 910 + if (crtc_state->enable) 911 + drm_mode_get_hv_timing(&crtc_state->mode, &clip.x2, &clip.y2); 912 + 913 + plane_state->visible = drm_rect_clip_scaled(src, dst, &clip); 914 + drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation); 915 + } else if (drm_plane_solid_fill_enabled(plane_state)) { 916 + plane_state->visible = true; 903 917 } 904 - 905 - if (crtc_state->enable) 906 - drm_mode_get_hv_timing(&crtc_state->mode, &clip.x2, &clip.y2); 907 - 908 - plane_state->visible = drm_rect_clip_scaled(src, dst, &clip); 909 - 910 - drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation); 911 918 912 919 if (!plane_state->visible) 913 920 /*
+2 -2
include/drm/drm_atomic_helper.h
··· 256 256 * Anything else should be considered a bug in the atomic core, so we 257 257 * gently warn about it. 258 258 */ 259 - WARN_ON((new_plane_state->crtc == NULL && new_plane_state->fb != NULL) || 260 - (new_plane_state->crtc != NULL && new_plane_state->fb == NULL)); 259 + WARN_ON((new_plane_state->crtc == NULL && drm_plane_has_visible_data(new_plane_state)) || 260 + (new_plane_state->crtc != NULL && !drm_plane_has_visible_data(new_plane_state))); 261 261 262 262 return old_plane_state->crtc && !new_plane_state->crtc; 263 263 }
+29
include/drm/drm_plane.h
··· 1016 1016 #define drm_for_each_plane(plane, dev) \ 1017 1017 list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) 1018 1018 1019 + /** 1020 + * drm_plane_solid_fill_enabled - Check if solid fill is enabled on plane 1021 + * @state: plane state 1022 + * 1023 + * Returns: 1024 + * Whether the plane has been assigned a solid_fill_blob 1025 + */ 1026 + static inline bool drm_plane_solid_fill_enabled(struct drm_plane_state *state) 1027 + { 1028 + if (!state) 1029 + return false; 1030 + return state->pixel_source == DRM_PLANE_PIXEL_SOURCE_SOLID_FILL && state->solid_fill_blob; 1031 + } 1032 + 1033 + static inline bool drm_plane_has_visible_data(const struct drm_plane_state *state) 1034 + { 1035 + switch (state->pixel_source) { 1036 + case DRM_PLANE_PIXEL_SOURCE_NONE: 1037 + return false; 1038 + case DRM_PLANE_PIXEL_SOURCE_SOLID_FILL: 1039 + return state->solid_fill_blob != NULL; 1040 + case DRM_PLANE_PIXEL_SOURCE_FB: 1041 + default: 1042 + WARN_ON(state->pixel_source != DRM_PLANE_PIXEL_SOURCE_FB); 1043 + } 1044 + 1045 + return state->fb != NULL; 1046 + } 1047 + 1019 1048 bool drm_any_plane_has_format(struct drm_device *dev, 1020 1049 u32 format, u64 modifier); 1021 1050