From a2608bb35404318dd510999ab806ba3a8d7fd912 Mon Sep 17 00:00:00 2001 From: Mahadevan P Date: Tue, 11 Aug 2026 14:14:15 +0800 Subject: [PATCH] WORKAROUND: drm/msm/dp: Dump only active pixel stream blocks in snapshot Each DP stream has its own pixel clock, but the snapshot code unconditionally dumps all pixel stream register blocks. In SST mode only stream 0 is active, while the remaining pixel stream blocks may be present in the address space but left unclocked. Accessing those registers during snapshot collection can result in unclocked NoC accesses. Add a helper to query per-stream pixel clock status and dump pixel stream blocks only when the corresponding stream clock is enabled. This avoids accessing inactive pixel stream registers while still collecting snapshot data for active streams. Signed-off-by: Mahadevan P Signed-off-by: Yongxing Mou --- drivers/gpu/drm/msm/dp/dp_ctrl.c | 13 +++++++++++++ drivers/gpu/drm/msm/dp/dp_ctrl.h | 2 ++ drivers/gpu/drm/msm/dp/dp_display.c | 25 +++++++++++++++++-------- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index 80116e19fbbf4..4181898f51cbc 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -2414,6 +2414,19 @@ void msm_dp_ctrl_off_pixel_clk(struct msm_dp_ctrl *msm_dp_ctrl, enum msm_dp_stre } } +bool msm_dp_ctrl_stream_clk_on(struct msm_dp_ctrl *msm_dp_ctrl, + enum msm_dp_stream_id stream_id) +{ + struct msm_dp_ctrl_private *ctrl; + + if (stream_id >= DP_STREAM_MAX) + return false; + + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); + + return ctrl->stream_clks_on[stream_id]; +} + static int msm_dp_ctrl_process_phy_test_request(struct msm_dp_ctrl_private *ctrl, struct msm_dp_panel *panel) { diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h index 88a02d52f61c6..4279f673e2d8d 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.h +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h @@ -26,6 +26,8 @@ int msm_dp_ctrl_prepare_stream_on(struct msm_dp_ctrl *msm_dp_ctrl, void msm_dp_ctrl_off_link(struct msm_dp_ctrl *msm_dp_ctrl, struct msm_dp_panel *panel); void msm_dp_ctrl_off_pixel_clk(struct msm_dp_ctrl *msm_dp_ctrl, enum msm_dp_stream_id stream_id); +bool msm_dp_ctrl_stream_clk_on(struct msm_dp_ctrl *msm_dp_ctrl, + enum msm_dp_stream_id stream_id); void msm_dp_ctrl_push_idle(struct msm_dp_ctrl *msm_dp_ctrl); void msm_dp_ctrl_push_vcpf(struct msm_dp_ctrl *msm_dp_ctrl, struct msm_dp_panel *panel); irqreturn_t msm_dp_ctrl_isr(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 8a75990d1055a..30ddc0eaa8a94 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -936,6 +936,7 @@ int msm_dp_display_get_test_bpp(struct msm_dp *dp) void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp) { struct msm_dp_display_private *msm_dp_display; + int i; msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display); @@ -959,14 +960,22 @@ void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp) msm_dp_display->mst2link_base, "dp_mst2link"); msm_disp_snapshot_add_block(disp_state, msm_dp_display->mst3link_len, msm_dp_display->mst3link_base, "dp_mst3link"); - msm_disp_snapshot_add_block(disp_state, msm_dp_display->pixel_len, - msm_dp_display->pixel_base[0], "dp_p0"); - msm_disp_snapshot_add_block(disp_state, msm_dp_display->pixel_len, - msm_dp_display->pixel_base[1], "dp_p1"); - msm_disp_snapshot_add_block(disp_state, msm_dp_display->pixel_len, - msm_dp_display->pixel_base[2], "dp_p2"); - msm_disp_snapshot_add_block(disp_state, msm_dp_display->pixel_len, - msm_dp_display->pixel_base[3], "dp_p3"); + + /* + * Each pixel stream is fed by its own pixel clock, and active_stream_cnt + * only tells us that at least one of them is running. Dump a per-stream + * block only when it is both mapped and its pixel clock is enabled: in + * SST only stream 0 is used, so reading the others - present in the IO + * space but unclocked - would trigger an unclocked (NoC) access. + */ + for (i = 0; i < DP_STREAM_MAX; i++) { + if (!msm_dp_display->pixel_base[i] || + !msm_dp_ctrl_stream_clk_on(msm_dp_display->ctrl, i)) + continue; + + msm_disp_snapshot_add_block(disp_state, msm_dp_display->pixel_len, + msm_dp_display->pixel_base[i], "dp_p%d", i); + } } void msm_dp_display_set_psr(struct msm_dp *msm_dp_display, bool enter)