[PATCH v2 16/20] drm/msm/dp: Disable PSR for YUV420 streams

From: Xilin Wu

Date: Thu Oct 08 2026 - 23:23:29 EST


YUV420 uses colorimetry VSC packets, which cannot share the automatic
PSR packet generator. Do not advertise self-refresh eligibility for
these streams while disabling PSR in the controller and sink.

Compute eligibility after the common atomic check and reject an
incompatible self-refresh entry. Clear the automatic VSC generation bit
for YUV420 and restore PSR configuration when returning to RGB.

Assisted-by: LLM
Signed-off-by: Xilin Wu <sophon@xxxxxxxxx>
---
drivers/gpu/drm/msm/dp/dp_ctrl.c | 19 ++++++++++++-------
drivers/gpu/drm/msm/dp/dp_ctrl.h | 2 +-
drivers/gpu/drm/msm/dp/dp_display.c | 3 ++-
drivers/gpu/drm/msm/dp/dp_drm.c | 16 ++++++++++++----
4 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 783cafb22374..82ef8e405543 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -411,7 +411,7 @@ static void msm_dp_ctrl_config_ctrl_streams(struct msm_dp_ctrl_private *ctrl,

config |= tbd << DP_CONFIGURATION_CTRL_BPC_SHIFT;

- if (msm_dp_panel->psr_cap.version)
+ if (msm_dp_panel->psr_cap.version && !msm_dp_panel->msm_dp_mode.out_fmt_is_yuv_420)
config |= DP_CONFIGURATION_CTRL_SEND_VSC;

drm_dbg_dp(ctrl->drm_dev, "stream DP_CONFIGURATION_CTRL=0x%x\n", config);
@@ -1914,7 +1914,7 @@ static void msm_dp_ctrl_psr_exit(struct msm_dp_ctrl_private *ctrl)
}

void msm_dp_ctrl_config_psr(struct msm_dp_ctrl *msm_dp_ctrl,
- struct msm_dp_panel *panel)
+ struct msm_dp_panel *panel, bool enable)
{
struct msm_dp_ctrl_private *ctrl = container_of(msm_dp_ctrl,
struct msm_dp_ctrl_private, msm_dp_ctrl);
@@ -1923,15 +1923,20 @@ void msm_dp_ctrl_config_psr(struct msm_dp_ctrl *msm_dp_ctrl,
if (!panel->psr_cap.version)
return;

- /* enable PSR1 function */
+ /* Colorimetry VSC packets cannot share the PSR packet generator. */
cfg = msm_dp_read_link(ctrl, REG_PSR_CONFIG);
- cfg |= PSR1_SUPPORTED;
+ if (enable)
+ cfg |= PSR1_SUPPORTED;
+ else
+ cfg &= ~PSR1_SUPPORTED;
msm_dp_write_link(ctrl, REG_PSR_CONFIG, cfg);

- msm_dp_ctrl_config_psr_interrupt(ctrl);
- msm_dp_ctrl_enable_sdp(ctrl);
+ if (enable) {
+ msm_dp_ctrl_config_psr_interrupt(ctrl);
+ msm_dp_ctrl_enable_sdp(ctrl);
+ }

- cfg = DP_PSR_ENABLE;
+ cfg = enable ? DP_PSR_ENABLE : 0;
drm_dp_dpcd_write(ctrl->aux, DP_PSR_EN_CFG, &cfg, 1);
}

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h
index 42c5f847cb02..4dd604ef9f1b 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.h
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h
@@ -46,7 +46,7 @@ void msm_dp_ctrl_irq_phy_exit(struct msm_dp_ctrl *msm_dp_ctrl);
void msm_dp_ctrl_set_psr(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel, bool enable);
void msm_dp_ctrl_config_psr(struct msm_dp_ctrl *msm_dp_ctrl,
- struct msm_dp_panel *panel);
+ struct msm_dp_panel *panel, bool enable);

int msm_dp_ctrl_core_clk_enable(struct msm_dp_ctrl *msm_dp_ctrl);
void msm_dp_ctrl_core_clk_disable(struct msm_dp_ctrl *msm_dp_ctrl);
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 486348113b8a..234cb2373451 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -822,7 +822,8 @@ static int msm_dp_display_post_enable(struct msm_dp *msm_dp_display)
msm_dp_display_handle_plugged_change(msm_dp_display, true);

if (msm_dp_display->psr_supported)
- msm_dp_ctrl_config_psr(dp->ctrl, dp->panel);
+ msm_dp_ctrl_config_psr(dp->ctrl, dp->panel,
+ !dp->panel->msm_dp_mode.out_fmt_is_yuv_420);

return 0;
}
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 9f1aa87a3687..6b01eeeb1aef 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -204,19 +204,27 @@ static int msm_edp_bridge_atomic_check(struct drm_bridge *drm_bridge,
struct drm_connector_state *conn_state)
{
struct msm_dp *dp = to_dp_bridge(drm_bridge)->msm_dp_display;
+ int ret;

if (WARN_ON(!conn_state))
return -ENODEV;

- conn_state->self_refresh_aware = dp->psr_supported;
-
+ conn_state->self_refresh_aware = false;
if (!conn_state->crtc || !crtc_state)
return 0;

- if (crtc_state->self_refresh_active && !dp->psr_supported)
+ ret = msm_dp_bridge_atomic_check(drm_bridge, bridge_state, crtc_state, conn_state);
+ if (ret)
+ return ret;
+
+ /* Match the PSR configuration applied when enabling this stream. */
+ conn_state->self_refresh_aware = dp->psr_supported &&
+ !drm_mode_is_420_only(&conn_state->connector->display_info,
+ &crtc_state->adjusted_mode);
+ if (crtc_state->self_refresh_active && !conn_state->self_refresh_aware)
return -EINVAL;

- return msm_dp_bridge_atomic_check(drm_bridge, bridge_state, crtc_state, conn_state);
+ return 0;
}

static void msm_edp_bridge_atomic_enable(struct drm_bridge *drm_bridge,

--
2.56.0