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

Configure Feed

Select the types of activity you want to include in your feed.

drm/msm/dpu: don't set crtc_state->mode_changed from atomic_check()

The MSM driver uses drm_atomic_helper_check() which mandates that none
of the atomic_check() callbacks toggles crtc_state->mode_changed.
Perform corresponding check before calling the drm_atomic_helper_check()
function.

Fixes: 8b45a26f2ba9 ("drm/msm/dpu: reserve cdm blocks for writeback in case of YUV output")
Reported-by: Simona Vetter <simona.vetter@ffwll.ch>
Closes: https://lore.kernel.org/dri-devel/ZtW_S0j5AEr4g0QW@phenom.ffwll.local/
Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
[DB: dropped the WARN_ON]
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Patchwork: https://patchwork.freedesktop.org/patch/633400/
Link: https://lore.kernel.org/r/20250123-drm-dirty-modeset-v2-4-bbfd3a6cd1a4@linaro.org

+75 -5
+28 -4
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
··· 760 760 cstate->num_mixers = num_lm; 761 761 } 762 762 763 + /** 764 + * dpu_encoder_virt_check_mode_changed: check if full modeset is required 765 + * @drm_enc: Pointer to drm encoder structure 766 + * @crtc_state: Corresponding CRTC state to be checked 767 + * @conn_state: Corresponding Connector's state to be checked 768 + * 769 + * Check if the changes in the object properties demand full mode set. 770 + */ 771 + int dpu_encoder_virt_check_mode_changed(struct drm_encoder *drm_enc, 772 + struct drm_crtc_state *crtc_state, 773 + struct drm_connector_state *conn_state) 774 + { 775 + struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); 776 + struct msm_display_topology topology; 777 + 778 + DPU_DEBUG_ENC(dpu_enc, "\n"); 779 + 780 + /* Using mode instead of adjusted_mode as it wasn't computed yet */ 781 + topology = dpu_encoder_get_topology(dpu_enc, &crtc_state->mode, crtc_state, conn_state); 782 + 783 + if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm) 784 + crtc_state->mode_changed = true; 785 + else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm) 786 + crtc_state->mode_changed = true; 787 + 788 + return 0; 789 + } 790 + 763 791 static int dpu_encoder_virt_atomic_check( 764 792 struct drm_encoder *drm_enc, 765 793 struct drm_crtc_state *crtc_state, ··· 821 793 822 794 topology = dpu_encoder_get_topology(dpu_enc, adj_mode, crtc_state, conn_state); 823 795 824 - if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm) 825 - crtc_state->mode_changed = true; 826 - else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm) 827 - crtc_state->mode_changed = true; 828 796 /* 829 797 * Release and Allocate resources on every modeset 830 798 */
+4
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
··· 88 88 89 89 bool dpu_encoder_is_valid_for_commit(struct drm_encoder *drm_enc); 90 90 91 + int dpu_encoder_virt_check_mode_changed(struct drm_encoder *drm_enc, 92 + struct drm_crtc_state *crtc_state, 93 + struct drm_connector_state *conn_state); 94 + 91 95 #endif /* __DPU_ENCODER_H__ */
+24
drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
··· 446 446 pm_runtime_put_sync(&dpu_kms->pdev->dev); 447 447 } 448 448 449 + static int dpu_kms_check_mode_changed(struct msm_kms *kms, struct drm_atomic_state *state) 450 + { 451 + struct drm_crtc_state *new_crtc_state; 452 + struct drm_connector *connector; 453 + struct drm_connector_state *new_conn_state; 454 + int i; 455 + 456 + for_each_new_connector_in_state(state, connector, new_conn_state, i) { 457 + struct drm_encoder *encoder; 458 + 459 + if (!new_conn_state->crtc || !new_conn_state->best_encoder) 460 + continue; 461 + 462 + new_crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc); 463 + 464 + encoder = new_conn_state->best_encoder; 465 + 466 + dpu_encoder_virt_check_mode_changed(encoder, new_crtc_state, new_conn_state); 467 + } 468 + 469 + return 0; 470 + } 471 + 449 472 static void dpu_kms_flush_commit(struct msm_kms *kms, unsigned crtc_mask) 450 473 { 451 474 struct dpu_kms *dpu_kms = to_dpu_kms(kms); ··· 1085 1062 .irq = dpu_core_irq, 1086 1063 .enable_commit = dpu_kms_enable_commit, 1087 1064 .disable_commit = dpu_kms_disable_commit, 1065 + .check_mode_changed = dpu_kms_check_mode_changed, 1088 1066 .flush_commit = dpu_kms_flush_commit, 1089 1067 .wait_flush = dpu_kms_wait_flush, 1090 1068 .complete_commit = dpu_kms_complete_commit,
+12 -1
drivers/gpu/drm/msm/msm_atomic.c
··· 183 183 184 184 int msm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) 185 185 { 186 + struct msm_drm_private *priv = dev->dev_private; 187 + struct msm_kms *kms = priv->kms; 186 188 struct drm_crtc_state *old_crtc_state, *new_crtc_state; 187 189 struct drm_crtc *crtc; 188 - int i; 190 + int i, ret = 0; 189 191 192 + /* 193 + * FIXME: stop setting allow_modeset and move this check to the DPU 194 + * driver. 195 + */ 190 196 for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, 191 197 new_crtc_state, i) { 192 198 if ((old_crtc_state->ctm && !new_crtc_state->ctm) || ··· 201 195 state->allow_modeset = true; 202 196 } 203 197 } 198 + 199 + if (kms && kms->funcs && kms->funcs->check_mode_changed) 200 + ret = kms->funcs->check_mode_changed(kms, state); 201 + if (ret) 202 + return ret; 204 203 205 204 return drm_atomic_helper_check(dev, state); 206 205 }
+7
drivers/gpu/drm/msm/msm_kms.h
··· 60 60 void (*disable_commit)(struct msm_kms *kms); 61 61 62 62 /** 63 + * @check_mode_changed: 64 + * 65 + * Verify if the commit requires a full modeset on one of CRTCs. 66 + */ 67 + int (*check_mode_changed)(struct msm_kms *kms, struct drm_atomic_state *state); 68 + 69 + /** 63 70 * Prepare for atomic commit. This is called after any previous 64 71 * (async or otherwise) commit has completed. 65 72 */