On 4/12/2026 2:07 AM, Dmitry Baryshkov wrote:
In this series, panel come with MST connectors, Because the connectors are dynamically assigned, we don’t know which connector corresponds to which stream, so there stream_id and pixel base address are dynamic.On Fri, Apr 10, 2026 at 05:33:50PM +0800, Yongxing Mou wrote:From: Abhinav Kumar <[email protected]> Add support for additional pixel register blocks (p1, p2, p3) to enable 4‑stream MST pixel clocks. Introduce the helper functions msm_dp_read_pn and msm_dp_write_pn for pixel register programming. All pixel clocks share the same register layout but use different base addresses. Signed-off-by: Abhinav Kumar <[email protected]> Signed-off-by: Yongxing Mou <[email protected]> --- drivers/gpu/drm/msm/dp/dp_display.c | 40 ++++++++++++----- drivers/gpu/drm/msm/dp/dp_panel.c | 89 ++++++++++++++++++++----------------- drivers/gpu/drm/msm/dp/dp_panel.h | 3 +- 3 files changed, 79 insertions(+), 53 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 7984a0f9e938..ff506064a3fa 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -85,8 +85,8 @@ struct msm_dp_display_private { void __iomem *link_base; size_t link_len;- void __iomem *p0_base;- size_t p0_len; + void __iomem *pixel_base[DP_STREAM_MAX]; + size_t pixel_len;int max_stream;}; @@ -561,7 +561,7 @@ static int msm_dp_init_sub_modules(struct msm_dp_display_private *dp) goto error_link; }- dp->panel = msm_dp_panel_get(dev, dp->aux, dp->link, dp->link_base, dp->p0_base);+ dp->panel = msm_dp_panel_get(dev, dp->aux, dp->link, dp->link_base, dp->pixel_base[0]); if (IS_ERR(dp->panel)) { rc = PTR_ERR(dp->panel); DRM_ERROR("failed to initialize panel, rc = %d\n", rc); @@ -769,6 +769,7 @@ int msm_dp_display_set_stream_info(struct msm_dp *msm_dp_display, }panel->stream_id = stream_id;+ msm_dp_panel_set_pixel_base(panel, dp->pixel_base[stream_id]);Hmmm.... Would it be better to set it up differently? Allocate one panel per the stream from the beginning and then simply get the first available panel when required? This would require some minimal resource manager, but then we won't have to pass dummy register base to the panel code. Or actually allocate a panel when it is required? Do we need a panel before atomic_enable()?
we have 2 optionals here:
1.panel come with encoder (after bridge remvoed), like that:
struct msm_dp_mst_encoder {
struct drm_encoder *enc;
int stream_id;
struct msm_dp_panel *dp_panel;
};
2. During enable and disable, allocate and release dynamically.
would you prefer which one?
return rc;} @@ -882,8 +883,14 @@ void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp) msm_dp_display->aux_base, "dp_aux"); msm_disp_snapshot_add_block(disp_state, msm_dp_display->link_len, msm_dp_display->link_base, "dp_link"); - msm_disp_snapshot_add_block(disp_state, msm_dp_display->p0_len, - msm_dp_display->p0_base, "dp_p0"); + 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"); }void msm_dp_display_set_psr(struct msm_dp *msm_dp_display, bool enter)@@ -1163,6 +1170,7 @@ static void __iomem *msm_dp_ioremap(struct platform_device *pdev, int idx, size_ static int msm_dp_display_get_io(struct msm_dp_display_private *display) { struct platform_device *pdev = display->msm_dp_display.pdev; + int i;display->ahb_base = msm_dp_ioremap(pdev, 0, &display->ahb_len);if (IS_ERR(display->ahb_base)) @@ -1192,8 +1200,8 @@ static int msm_dp_display_get_io(struct msm_dp_display_private *display) display->aux_len = DP_DEFAULT_AUX_SIZE; display->link_base = display->ahb_base + DP_DEFAULT_LINK_OFFSET; display->link_len = DP_DEFAULT_LINK_SIZE; - display->p0_base = display->ahb_base + DP_DEFAULT_P0_OFFSET; - display->p0_len = DP_DEFAULT_P0_SIZE; + display->pixel_base[0] = display->ahb_base + DP_DEFAULT_P0_OFFSET; + display->pixel_len = DP_DEFAULT_P0_SIZE;return 0;} @@ -1204,10 +1212,20 @@ static int msm_dp_display_get_io(struct msm_dp_display_private *display) return PTR_ERR(display->link_base); }- display->p0_base = msm_dp_ioremap(pdev, 3, &display->p0_len);- if (IS_ERR(display->p0_base)) { - DRM_ERROR("unable to remap p0 region: %pe\n", display->p0_base); - return PTR_ERR(display->p0_base); + display->pixel_base[0] = msm_dp_ioremap(pdev, 3, &display->pixel_len); + if (IS_ERR(display->pixel_base[0])) { + DRM_ERROR("unable to remap p0 region: %pe\n", display->pixel_base[0]); + return PTR_ERR(display->pixel_base[0]); + } + + for (i = DP_STREAM_1; i < display->max_stream; i++) { + /* pixels clk reg index start from 3*/ + display->pixel_base[i] = msm_dp_ioremap(pdev, i + 3, &display->pixel_len); + if (IS_ERR(display->pixel_base[i])) { + DRM_DEBUG_DP("unable to remap p%d region: %pe\n", i, + display->pixel_base[i]); + break;No, return an error.
Got it.
+ } }return 0;
