public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface
@ 2025-09-18 13:28 Jun Nie
  2025-09-18 13:28 ` [PATCH v16 01/10] drm/msm/dpu: fix mixer number counter on allocation Jun Nie
                   ` (11 more replies)
  0 siblings, 12 replies; 28+ messages in thread
From: Jun Nie @ 2025-09-18 13:28 UTC (permalink / raw)
  To: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, Jessica Zhang
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jun Nie,
	Jessica Zhang, Dmitry Baryshkov, Dmitry Baryshkov

2 or more SSPPs and dual-DSI interface are need for super wide panel.
And 4 DSC are preferred for power optimal in this case due to width
limitation of SSPP and MDP clock rate constrain. This patch set
extends number of pipes to 4 and revise related mixer blending logic
to support quad pipe. All these changes depends on the virtual plane
feature to split a super wide drm plane horizontally into 2 or more sub
clip. Thus DMA of multiple SSPPs can share the effort of fetching the
whole drm plane.

The first pipe pair co-work with the first mixer pair to cover the left
half of screen and 2nd pair of pipes and mixers are for the right half
of screen. If a plane is only for the right half of screen, only one
or two of pipes in the 2nd pipe pair are valid, and no SSPP or mixer is
assinged for invalid pipe.

For those panel that does not require quad-pipe, only 1 or 2 pipes in
the 1st pipe pair will be used. There is no concept of right half of
screen.

For legacy non virtual plane mode, the first 1 or 2 pipes are used for
the single SSPP and its multi-rect mode.
    
    Changes in v16:
    - Rebase to latest branch msm-next-lumag.
    - Fix IGT test failures.
    - Drop patches that have been merged.
    - Link to v15: https://lore.kernel.org/r/20250819-v6-16-rc2-quad-pipe-upstream-v15-0-2c7a85089db8@linaro.org
    
    Changes in v15:
    - Polish logic in sspp check and assignment.
    - Link to v14: https://lore.kernel.org/r/20250801-v6-16-rc2-quad-pipe-upstream-v14-0-b626236f4c31@linaro.org
    
    Changes in v14:
    - Add patch to fix null pointer bug SSPP sharing, which is missed in
      the last version.
    - Polish single pipe check with removing loop.
    - Polish logic of SSPP sharing test in dpu_plane_virtual_assign_resources()
    - Polish argument of dpu_plane_virtual_assign_resources().
    - Link to v13: https://lore.kernel.org/r/20250728-v6-16-rc2-quad-pipe-upstream-v13-0-954e4917fe4f@linaro.org
    
    Changes in v13:
    - Modify the SSPP assignment patch for sharing SSPP among planes in
      quad-pipe case.
    - Link to v12: https://lore.kernel.org/r/20250707-v6-16-rc2-quad-pipe-upstream-v12-0-67e3721e7d83@linaro.org
    
    Changes in v12:
    - Polish single pipe case detection in a plane. Add stage index check when
      sharing SSPP with multi-rect mode in 2 planes.
    - Abstract SSPP assignment in a stage into a function.
    - Rebase to latest msm/msm-next.
    - Link to v11: https://lore.kernel.org/r/20250603-v6-15-quad-pipe-upstream-v11-0-c3af7190613d@linaro.org
    
    Changes in v11:
    - Change function name from dpu_plane_check_single_pipe to
      dpu_plane_get_single_pipe.
    - Abstract SSPP assignment in stage into a function.
    - Link to v10: https://lore.kernel.org/r/20250526-v6-15-quad-pipe-upstream-v10-0-5fed4f8897c4@linaro.org
    
    Changes in v10:
    - Drop changes in drm helper side, because num_lm == 0 does not lead to
      any issue in the first call to dpu_plane_atomic_check_nosspp() with
      latest repo. It is initialized properly right after the call in
      drm_atomic_helper_check_planes(), thus the later plane splitting works
      as expected.
    - Rebase to latest msm-next branch.
    - Fix PIPES_PER_STAGE to PIPES_PER_PLANE where handling all pipes, instead
      of stages.
    - Link to v9: https://lore.kernel.org/r/20250506-quad-pipe-upstream-v9-0-f7b273a8cc80@linaro.org
    
    Changes in v9:
    - Rebase to latest mainline and drop 3 patches as mainline already cover
      the logic.
      "Do not fix number of DSC"
      "configure DSC per number in use"
      "switch RM to use crtc_id rather than enc_id for allocation"
    - Add a patch to check crtc before checking plane in drm framework.
    - Add a patch to use dedicated WB number in an encoder to avoid regression.
    - Revise the condition to decide quad-pipe topology.
    - Link to v8: https://lore.kernel.org/r/20250303-sm8650-v6-14-hmd-deckard-mdss-quad-upstream-oldbootwrapper-36-prep-v8-0-eb5df105c807@linaro.org
    
    Changes in v8:
    - Fix looping pipes of a plane in _dpu_plane_color_fill()
    - Improve pipe assignment with deleting pipes loop in stage.
    - Define PIPES_PER_PLANE properly when it appears fisrt.
    - rename lms_in_pair to lms_in_stage to avoid confusion.
    - Add review tags.
    - Link to v7: https://lore.kernel.org/r/20250226-sm8650-v6-14-hmd-deckard-mdss-quad-upstream-oldbootwrapper-36-prep-v7-0-8d5f5f426eb2@linaro.org
    
    Changes in v7:
    - Improve pipe assignment to avoid point to invalid memory.
    - Define STAGES_PER_PLANE as 2 only when quad-pipe is introduced.
    - Polish LM number when blending pipes with min() and pull up to caller func.
    - Add review tags.
    - Link to v6: https://lore.kernel.org/r/20250217-sm8650-v6-14-hmd-deckard-mdss-quad-upstream-oldbootwrapper-36-prep-v6-0-c11402574367@linaro.org
    
    Changes in v6:
    - Replace LM number with PP number to calculate PP number per encoder.
    - Rebase to Linux v6.14-rc2.
    - Add review tags.
    - Link to v5: https://lore.kernel.org/r/20250118-sm8650-v6-13-hmd-deckard-mdss-quad-upstream-33-v5-0-9701a16340da@linaro.org
    
    Changes in v5:
    - Iterate SSPP flushing within the required mixer pair, instead of all
      active mixers or specific mixer.
    - Limit qaud-pipe usage case to SoC with 4 or more DSC engines and 2
      interfaces case.
    - Remove valid flag and use width for pipe validation.
    - Polish commit messages and code comments.
    - Link to v4: https://lore.kernel.org/r/20250116-sm8650-v6-13-hmd-deckard-mdss-quad-upstream-33-v4-0-74749c6eba33@linaro.org
    
    Changes in v4:
    - Restrict SSPP flushing to the required mixer, instead of all active mixers.
    - Polish commit messages and code comments.
    - Rebase to latest msm/drm-next branch.
    - Move pipe checking patch to the top of patch set.
    - Link to v3: https://lore.kernel.org/dri-devel/20241219-sm8650-v6-13-hmd-deckard-mdss-quad-upstream-32-v3-0-92c7c0a228e3@linaro.org
    
    Changes in v3:
    - Split change in trace into a separate patch.
    - Rebase to latest msm-next branch.
    - Reorder patch sequence to make sure valid flag is set in earlier patch
    - Rectify rewrite patch to move logic change into other patch
    - Polish commit messages and code comments.
    - Link to v2: https://lore.kernel.org/dri-devel/20241009-sm8650-v6-11-hmd-pocf-mdss-quad-upstream-21-v2-0-76d4f5d413bf@linaro.org
    
    Changes in v2:
    - Revise the patch sequence with changing to 2 pipes topology first. Then
      prepare for quad-pipe setup, then enable quad-pipe at last.
    - Split DSI patches into other patch set.
    - Link to v1: https://lore.kernel.org/all/20240829-sm8650-v6-11-hmd-pocf-mdss-quad-upstream-8-v1-0-bdb05b4b5a2e@linaro.org
    

Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
Jun Nie (10):
      drm/msm/dpu: fix mixer number counter on allocation
      drm/msm/dpu: bind correct pingpong for quad pipe
      drm/msm/dpu: Add pipe as trace argument
      drm/msm/dpu: handle pipes as array
      drm/msm/dpu: split PIPES_PER_STAGE definition per plane and mixer
      drm/msm/dpu: Use dedicated WB number definition
      drm/msm/dpu: blend pipes per mixer pairs config
      drm/msm/dpu: support SSPP assignment for quad-pipe case
      drm/msm/dpu: support plane splitting in quad-pipe case
      drm/msm/dpu: Enable quad-pipe for DSC and dual-DSI case

 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c         | 115 +++---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h         |   8 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c      |  43 ++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h |   2 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h   |   2 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h      |   2 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c        | 428 ++++++++++++++---------
 drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h        |  12 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c           |   6 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h        |  10 +-
 10 files changed, 380 insertions(+), 248 deletions(-)
---
base-commit: 01f31f83a125db48c058e1864cbfe877c086b6fb
change-id: 20250918-v6-16-rc2-quad-pipe-upstream-4-c871c0c93bc0

Best regards,
-- 
Jun Nie <jun.nie@linaro.org>


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v16 01/10] drm/msm/dpu: fix mixer number counter on allocation
  2025-09-18 13:28 [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface Jun Nie
@ 2025-09-18 13:28 ` Jun Nie
  2025-09-18 13:28 ` [PATCH v16 02/10] drm/msm/dpu: bind correct pingpong for quad pipe Jun Nie
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 28+ messages in thread
From: Jun Nie @ 2025-09-18 13:28 UTC (permalink / raw)
  To: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, Jessica Zhang
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jun Nie,
	Jessica Zhang, Dmitry Baryshkov

Current code only supports usage cases with one pair of mixers at
most. To support quad-pipe usage case, two pairs of mixers need to
be reserved. The lm_count for all pairs is cleared if a peer
allocation fails in current implementation. Reset the current lm_count
to an even number instead of completely clearing it. This prevents all
pairs from being cleared in cases where multiple LM pairs are needed.

Signed-off-by: Jun Nie <jun.nie@linaro.org>
Reviewed-by: Jessica Zhang <quic_jesszhan@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
index 2c77c74fac0fda649da8ce19b7b3c6cb32b9535c..3f344322b7f214d0050986e675b32522f8eb0ba7 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
@@ -374,7 +374,11 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm,
 		if (!rm->mixer_blks[i])
 			continue;
 
-		lm_count = 0;
+		/*
+		 * Reset lm_count to an even index. This will drop the previous
+		 * primary mixer if failed to find its peer.
+		 */
+		lm_count &= ~1;
 		lm_idx[lm_count] = i;
 
 		if (!_dpu_rm_check_lm_and_get_connected_blks(rm, global_state,

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v16 02/10] drm/msm/dpu: bind correct pingpong for quad pipe
  2025-09-18 13:28 [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface Jun Nie
  2025-09-18 13:28 ` [PATCH v16 01/10] drm/msm/dpu: fix mixer number counter on allocation Jun Nie
@ 2025-09-18 13:28 ` Jun Nie
  2025-09-18 13:28 ` [PATCH v16 03/10] drm/msm/dpu: Add pipe as trace argument Jun Nie
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 28+ messages in thread
From: Jun Nie @ 2025-09-18 13:28 UTC (permalink / raw)
  To: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, Jessica Zhang
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jun Nie,
	Jessica Zhang, Dmitry Baryshkov

There are 2 interfaces and 4 pingpong in quad pipe. Map the 2nd
interface to 3rd PP instead of the 2nd PP.

Signed-off-by: Jun Nie <jun.nie@linaro.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Jessica Zhang <quic_jesszhan@quicinc.com>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 258edaa18fc02f837122c84842b59f2cee68d66e..1318f9e63ef1e7bab078ae17e39d9ed19c04f465 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1160,7 +1160,7 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
 	struct dpu_hw_blk *hw_ctl[MAX_CHANNELS_PER_ENC];
 	struct dpu_hw_blk *hw_dsc[MAX_CHANNELS_PER_ENC];
 	struct dpu_hw_blk *hw_cwb[MAX_CHANNELS_PER_ENC];
-	int num_ctl, num_pp, num_dsc;
+	int num_ctl, num_pp, num_dsc, num_pp_per_intf;
 	int num_cwb = 0;
 	bool is_cwb_encoder;
 	unsigned int dsc_mask = 0;
@@ -1239,10 +1239,16 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
 		dpu_enc->cur_master->hw_cdm = hw_cdm ? to_dpu_hw_cdm(hw_cdm) : NULL;
 	}
 
+	/*
+	 * There may be 4 PP and 2 INTF for quad pipe case, so INTF is not
+	 * mapped to PP 1:1. Let's calculate the stride with pipe/INTF
+	 */
+	num_pp_per_intf = num_pp / dpu_enc->num_phys_encs;
+
 	for (i = 0; i < dpu_enc->num_phys_encs; i++) {
 		struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
 
-		phys->hw_pp = dpu_enc->hw_pp[i];
+		phys->hw_pp = dpu_enc->hw_pp[num_pp_per_intf * i];
 		if (!phys->hw_pp) {
 			DPU_ERROR_ENC(dpu_enc,
 				"no pp block assigned at idx: %d\n", i);

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v16 03/10] drm/msm/dpu: Add pipe as trace argument
  2025-09-18 13:28 [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface Jun Nie
  2025-09-18 13:28 ` [PATCH v16 01/10] drm/msm/dpu: fix mixer number counter on allocation Jun Nie
  2025-09-18 13:28 ` [PATCH v16 02/10] drm/msm/dpu: bind correct pingpong for quad pipe Jun Nie
@ 2025-09-18 13:28 ` Jun Nie
  2025-09-18 13:28 ` [PATCH v16 04/10] drm/msm/dpu: handle pipes as array Jun Nie
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 28+ messages in thread
From: Jun Nie @ 2025-09-18 13:28 UTC (permalink / raw)
  To: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, Jessica Zhang
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jun Nie,
	Jessica Zhang, Dmitry Baryshkov

Add pipe as trace argument in trace_dpu_crtc_setup_mixer() to ease
converting pipe into pipe array later.

Signed-off-by: Jun Nie <jun.nie@linaro.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Jessica Zhang <quic_jesszhan@quicinc.com>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c  |  2 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h | 10 +++++-----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 4b970a59deafdae3eb964da912e7f1f1d181eec7..f47e961de51265941820bb8d1081eed925b286fd 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -419,7 +419,7 @@ static void _dpu_crtc_blend_setup_pipe(struct drm_crtc *crtc,
 
 	trace_dpu_crtc_setup_mixer(DRMID(crtc), DRMID(plane),
 				   state, to_dpu_plane_state(state), stage_idx,
-				   format->pixel_format,
+				   format->pixel_format, pipe,
 				   modifier);
 
 	DRM_DEBUG_ATOMIC("crtc %d stage:%d - plane %d sspp %d fb %d multirect_idx %d\n",
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h
index 5307cbc2007c5044c5b897c53b44a8e356f1ad0f..cb24ad2a6d8d386bbc97b173854c410220725a0d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h
@@ -651,9 +651,9 @@ TRACE_EVENT(dpu_crtc_setup_mixer,
 	TP_PROTO(uint32_t crtc_id, uint32_t plane_id,
 		 struct drm_plane_state *state, struct dpu_plane_state *pstate,
 		 uint32_t stage_idx, uint32_t pixel_format,
-		 uint64_t modifier),
+		 struct dpu_sw_pipe *pipe, uint64_t modifier),
 	TP_ARGS(crtc_id, plane_id, state, pstate, stage_idx,
-		pixel_format, modifier),
+		pixel_format, pipe, modifier),
 	TP_STRUCT__entry(
 		__field(	uint32_t,		crtc_id		)
 		__field(	uint32_t,		plane_id	)
@@ -676,9 +676,9 @@ TRACE_EVENT(dpu_crtc_setup_mixer,
 		__entry->dst_rect = drm_plane_state_dest(state);
 		__entry->stage_idx = stage_idx;
 		__entry->stage = pstate->stage;
-		__entry->sspp = pstate->pipe.sspp->idx;
-		__entry->multirect_idx = pstate->pipe.multirect_index;
-		__entry->multirect_mode = pstate->pipe.multirect_mode;
+		__entry->sspp = pipe->sspp->idx;
+		__entry->multirect_idx = pipe->multirect_index;
+		__entry->multirect_mode = pipe->multirect_mode;
 		__entry->pixel_format = pixel_format;
 		__entry->modifier = modifier;
 	),

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v16 04/10] drm/msm/dpu: handle pipes as array
  2025-09-18 13:28 [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface Jun Nie
                   ` (2 preceding siblings ...)
  2025-09-18 13:28 ` [PATCH v16 03/10] drm/msm/dpu: Add pipe as trace argument Jun Nie
@ 2025-09-18 13:28 ` Jun Nie
  2025-09-18 13:28 ` [PATCH v16 05/10] drm/msm/dpu: split PIPES_PER_STAGE definition per plane and mixer Jun Nie
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 28+ messages in thread
From: Jun Nie @ 2025-09-18 13:28 UTC (permalink / raw)
  To: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, Jessica Zhang
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jun Nie,
	Jessica Zhang, Dmitry Baryshkov

There are 2 pipes in a drm plane at most currently, while 4 pipes are
required for quad-pipe case. Generalize the handling to pipe pair and
ease handling to another pipe pair later. Store pipes in array with
removing dedicated r_pipe.

Signed-off-by: Jun Nie <jun.nie@linaro.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Jessica Zhang <quic_jesszhan@quicinc.com>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c  |  39 +++----
 drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 178 ++++++++++++++++--------------
 drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h |  12 +-
 3 files changed, 118 insertions(+), 111 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index f47e961de51265941820bb8d1081eed925b286fd..c69b63f858329f60908fa7544fb2e5b3aba88540 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -449,7 +449,7 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
 	struct dpu_plane_state *pstate = NULL;
 	const struct msm_format *format;
 	struct dpu_hw_ctl *ctl = mixer->lm_ctl;
-	u32 lm_idx;
+	u32 lm_idx, i;
 	bool bg_alpha_enable = false;
 	DECLARE_BITMAP(active_fetch, SSPP_MAX);
 	DECLARE_BITMAP(active_pipes, SSPP_MAX);
@@ -472,22 +472,17 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
 		if (pstate->stage == DPU_STAGE_BASE && format->alpha_enable)
 			bg_alpha_enable = true;
 
-		set_bit(pstate->pipe.sspp->idx, active_fetch);
-		set_bit(pstate->pipe.sspp->idx, active_pipes);
-		_dpu_crtc_blend_setup_pipe(crtc, plane,
-					   mixer, cstate->num_mixers,
-					   pstate->stage,
-					   format, fb ? fb->modifier : 0,
-					   &pstate->pipe, 0, stage_cfg);
-
-		if (pstate->r_pipe.sspp) {
-			set_bit(pstate->r_pipe.sspp->idx, active_fetch);
-			set_bit(pstate->r_pipe.sspp->idx, active_pipes);
+
+		for (i = 0; i < PIPES_PER_STAGE; i++) {
+			if (!pstate->pipe[i].sspp)
+				continue;
+			set_bit(pstate->pipe[i].sspp->idx, active_fetch);
+			set_bit(pstate->pipe[i].sspp->idx, active_pipes);
 			_dpu_crtc_blend_setup_pipe(crtc, plane,
 						   mixer, cstate->num_mixers,
 						   pstate->stage,
 						   format, fb ? fb->modifier : 0,
-						   &pstate->r_pipe, 1, stage_cfg);
+						   &pstate->pipe[i], i, stage_cfg);
 		}
 
 		/* blend config update */
@@ -1679,15 +1674,15 @@ static int _dpu_debugfs_status_show(struct seq_file *s, void *data)
 		seq_printf(s, "\tdst x:%4d dst_y:%4d dst_w:%4d dst_h:%4d\n",
 			state->crtc_x, state->crtc_y, state->crtc_w,
 			state->crtc_h);
-		seq_printf(s, "\tsspp[0]:%s\n",
-			   pstate->pipe.sspp->cap->name);
-		seq_printf(s, "\tmultirect[0]: mode: %d index: %d\n",
-			pstate->pipe.multirect_mode, pstate->pipe.multirect_index);
-		if (pstate->r_pipe.sspp) {
-			seq_printf(s, "\tsspp[1]:%s\n",
-				   pstate->r_pipe.sspp->cap->name);
-			seq_printf(s, "\tmultirect[1]: mode: %d index: %d\n",
-				   pstate->r_pipe.multirect_mode, pstate->r_pipe.multirect_index);
+
+		for (i = 0; i < PIPES_PER_STAGE; i++) {
+			if (!pstate->pipe[i].sspp)
+				continue;
+			seq_printf(s, "\tsspp[%d]:%s\n",
+				   i, pstate->pipe[i].sspp->cap->name);
+			seq_printf(s, "\tmultirect[%d]: mode: %d index: %d\n",
+				   i, pstate->pipe[i].multirect_mode,
+				   pstate->pipe[i].multirect_index);
 		}
 
 		seq_puts(s, "\n");
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index f54cf0faa1c7c8c00eb68b8b45ca2fc776f7f62f..5bcdfe7078f717a59dc5a4883702d921ecf2025b 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -620,6 +620,7 @@ static void _dpu_plane_color_fill(struct dpu_plane *pdpu,
 	struct msm_drm_private *priv = plane->dev->dev_private;
 	struct dpu_plane_state *pstate = to_dpu_plane_state(plane->state);
 	u32 fill_color = (color & 0xFFFFFF) | ((alpha & 0xFF) << 24);
+	int i;
 
 	DPU_DEBUG_PLANE(pdpu, "\n");
 
@@ -633,12 +634,13 @@ static void _dpu_plane_color_fill(struct dpu_plane *pdpu,
 		return;
 
 	/* update sspp */
-	_dpu_plane_color_fill_pipe(pstate, &pstate->pipe, &pstate->pipe_cfg.dst_rect,
-				   fill_color, fmt);
-
-	if (pstate->r_pipe.sspp)
-		_dpu_plane_color_fill_pipe(pstate, &pstate->r_pipe, &pstate->r_pipe_cfg.dst_rect,
+	for (i = 0; i < PIPES_PER_STAGE; i++) {
+		if (!pstate->pipe[i].sspp)
+			continue;
+		_dpu_plane_color_fill_pipe(pstate, &pstate->pipe[i],
+					   &pstate->pipe_cfg[i].dst_rect,
 					   fill_color, fmt);
+	}
 }
 
 static int dpu_plane_prepare_fb(struct drm_plane *plane,
@@ -820,8 +822,8 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
 	struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);
 	u64 max_mdp_clk_rate = kms->perf.max_core_clk_rate;
 	struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state);
-	struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg;
-	struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg;
+	struct dpu_sw_pipe_cfg *pipe_cfg;
+	struct dpu_sw_pipe_cfg *r_pipe_cfg;
 	struct drm_rect fb_rect = { 0 };
 	uint32_t max_linewidth;
 
@@ -846,6 +848,9 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
 		return -EINVAL;
 	}
 
+	/* move the assignment here, to ease handling to another pairs later */
+	pipe_cfg = &pstate->pipe_cfg[0];
+	r_pipe_cfg = &pstate->pipe_cfg[1];
 	/* state->src is 16.16, src_rect is not */
 	drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src);
 
@@ -961,10 +966,10 @@ static int dpu_plane_atomic_check_sspp(struct drm_plane *plane,
 		drm_atomic_get_new_plane_state(state, plane);
 	struct dpu_plane *pdpu = to_dpu_plane(plane);
 	struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state);
-	struct dpu_sw_pipe *pipe = &pstate->pipe;
-	struct dpu_sw_pipe *r_pipe = &pstate->r_pipe;
-	struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg;
-	struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg;
+	struct dpu_sw_pipe *pipe = &pstate->pipe[0];
+	struct dpu_sw_pipe *r_pipe = &pstate->pipe[1];
+	struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg[0];
+	struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->pipe_cfg[1];
 	int ret = 0;
 
 	ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg,
@@ -1019,15 +1024,15 @@ static int dpu_plane_try_multirect_shared(struct dpu_plane_state *pstate,
 					  const struct msm_format *fmt,
 					  uint32_t max_linewidth)
 {
-	struct dpu_sw_pipe *pipe = &pstate->pipe;
-	struct dpu_sw_pipe *r_pipe = &pstate->r_pipe;
-	struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg;
-	struct dpu_sw_pipe *prev_pipe = &prev_adjacent_pstate->pipe;
-	struct dpu_sw_pipe_cfg *prev_pipe_cfg = &prev_adjacent_pstate->pipe_cfg;
+	struct dpu_sw_pipe *pipe = &pstate->pipe[0];
+	struct dpu_sw_pipe *r_pipe = &pstate->pipe[1];
+	struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg[0];
+	struct dpu_sw_pipe *prev_pipe = &prev_adjacent_pstate->pipe[0];
+	struct dpu_sw_pipe_cfg *prev_pipe_cfg = &prev_adjacent_pstate->pipe_cfg[0];
 	const struct msm_format *prev_fmt = msm_framebuffer_format(prev_adjacent_pstate->base.fb);
 	u16 max_tile_height = 1;
 
-	if (prev_adjacent_pstate->r_pipe.sspp != NULL ||
+	if (prev_adjacent_pstate->pipe[1].sspp != NULL ||
 	    prev_pipe->multirect_mode != DPU_SSPP_MULTIRECT_NONE)
 		return false;
 
@@ -1087,10 +1092,10 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
 	struct dpu_plane *pdpu = to_dpu_plane(plane);
 	struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state);
 	struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);
-	struct dpu_sw_pipe *pipe = &pstate->pipe;
-	struct dpu_sw_pipe *r_pipe = &pstate->r_pipe;
-	struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg;
-	struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg;
+	struct dpu_sw_pipe *pipe = &pstate->pipe[0];
+	struct dpu_sw_pipe *r_pipe = &pstate->pipe[1];
+	struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg[0];
+	struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->pipe_cfg[1];
 	const struct drm_crtc_state *crtc_state = NULL;
 	uint32_t max_linewidth = dpu_kms->catalog->caps->max_linewidth;
 
@@ -1134,7 +1139,7 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
 		drm_atomic_get_old_plane_state(state, plane);
 	struct dpu_plane_state *pstate = to_dpu_plane_state(plane_state);
 	struct drm_crtc_state *crtc_state = NULL;
-	int ret;
+	int ret, i;
 
 	if (IS_ERR(plane_state))
 		return PTR_ERR(plane_state);
@@ -1152,8 +1157,8 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
 		 * resources are freed by dpu_crtc_assign_plane_resources(),
 		 * but clean them here.
 		 */
-		pstate->pipe.sspp = NULL;
-		pstate->r_pipe.sspp = NULL;
+		for (i = 0; i < PIPES_PER_STAGE; i++)
+			pstate->pipe[i].sspp = NULL;
 
 		return 0;
 	}
@@ -1191,6 +1196,7 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
 	struct dpu_sw_pipe_cfg *pipe_cfg;
 	struct dpu_sw_pipe_cfg *r_pipe_cfg;
 	const struct msm_format *fmt;
+	int i;
 
 	if (plane_state->crtc)
 		crtc_state = drm_atomic_get_new_crtc_state(state,
@@ -1199,13 +1205,14 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
 	pstate = to_dpu_plane_state(plane_state);
 	prev_adjacent_pstate = prev_adjacent_plane_state ?
 		to_dpu_plane_state(prev_adjacent_plane_state) : NULL;
-	pipe = &pstate->pipe;
-	r_pipe = &pstate->r_pipe;
-	pipe_cfg = &pstate->pipe_cfg;
-	r_pipe_cfg = &pstate->r_pipe_cfg;
 
-	pipe->sspp = NULL;
-	r_pipe->sspp = NULL;
+	pipe = &pstate->pipe[0];
+	r_pipe = &pstate->pipe[1];
+	pipe_cfg = &pstate->pipe_cfg[0];
+	r_pipe_cfg = &pstate->pipe_cfg[1];
+
+	for (i = 0; i < PIPES_PER_STAGE; i++)
+		pstate->pipe[i].sspp = NULL;
 
 	if (!plane_state->fb)
 		return -EINVAL;
@@ -1316,6 +1323,7 @@ void dpu_plane_flush(struct drm_plane *plane)
 {
 	struct dpu_plane *pdpu;
 	struct dpu_plane_state *pstate;
+	int i;
 
 	if (!plane || !plane->state) {
 		DPU_ERROR("invalid plane\n");
@@ -1336,8 +1344,8 @@ void dpu_plane_flush(struct drm_plane *plane)
 		/* force 100% alpha */
 		_dpu_plane_color_fill(pdpu, pdpu->color_fill, 0xFF);
 	else {
-		dpu_plane_flush_csc(pdpu, &pstate->pipe);
-		dpu_plane_flush_csc(pdpu, &pstate->r_pipe);
+		for (i = 0; i < PIPES_PER_STAGE; i++)
+			dpu_plane_flush_csc(pdpu, &pstate->pipe[i]);
 	}
 
 	/* flag h/w flush complete */
@@ -1438,15 +1446,12 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane,
 	struct dpu_plane *pdpu = to_dpu_plane(plane);
 	struct drm_plane_state *state = plane->state;
 	struct dpu_plane_state *pstate = to_dpu_plane_state(state);
-	struct dpu_sw_pipe *pipe = &pstate->pipe;
-	struct dpu_sw_pipe *r_pipe = &pstate->r_pipe;
 	struct drm_crtc *crtc = state->crtc;
 	struct drm_framebuffer *fb = state->fb;
 	bool is_rt_pipe;
 	const struct msm_format *fmt =
 		msm_framebuffer_format(fb);
-	struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg;
-	struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg;
+	int i;
 
 	pstate->pending = true;
 
@@ -1461,12 +1466,12 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane,
 			crtc->base.id, DRM_RECT_ARG(&state->dst),
 			&fmt->pixel_format, MSM_FORMAT_IS_UBWC(fmt));
 
-	dpu_plane_sspp_update_pipe(plane, pipe, pipe_cfg, fmt,
-				   drm_mode_vrefresh(&crtc->mode),
-				   &pstate->layout);
-
-	if (r_pipe->sspp) {
-		dpu_plane_sspp_update_pipe(plane, r_pipe, r_pipe_cfg, fmt,
+	/* move the assignment here, to ease handling to another pairs later */
+	for (i = 0; i < PIPES_PER_STAGE; i++) {
+		if (!drm_rect_width(&pstate->pipe_cfg[i].src_rect))
+			continue;
+		dpu_plane_sspp_update_pipe(plane, &pstate->pipe[i],
+					   &pstate->pipe_cfg[i], fmt,
 					   drm_mode_vrefresh(&crtc->mode),
 					   &pstate->layout);
 	}
@@ -1474,15 +1479,17 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane,
 	if (pstate->needs_qos_remap)
 		pstate->needs_qos_remap = false;
 
-	pstate->plane_fetch_bw = _dpu_plane_calc_bw(pdpu->catalog, fmt,
-						    &crtc->mode, pipe_cfg);
-
-	pstate->plane_clk = _dpu_plane_calc_clk(&crtc->mode, pipe_cfg);
-
-	if (r_pipe->sspp) {
-		pstate->plane_fetch_bw += _dpu_plane_calc_bw(pdpu->catalog, fmt, &crtc->mode, r_pipe_cfg);
+	pstate->plane_fetch_bw = 0;
+	pstate->plane_clk = 0;
+	for (i = 0; i < PIPES_PER_STAGE; i++) {
+		if (!drm_rect_width(&pstate->pipe_cfg[i].src_rect))
+			continue;
+		pstate->plane_fetch_bw += _dpu_plane_calc_bw(pdpu->catalog, fmt,
+							     &crtc->mode, &pstate->pipe_cfg[i]);
 
-		pstate->plane_clk = max(pstate->plane_clk, _dpu_plane_calc_clk(&crtc->mode, r_pipe_cfg));
+		pstate->plane_clk = max(pstate->plane_clk,
+					_dpu_plane_calc_clk(&crtc->mode,
+							    &pstate->pipe_cfg[i]));
 	}
 }
 
@@ -1490,17 +1497,28 @@ static void _dpu_plane_atomic_disable(struct drm_plane *plane)
 {
 	struct drm_plane_state *state = plane->state;
 	struct dpu_plane_state *pstate = to_dpu_plane_state(state);
-	struct dpu_sw_pipe *r_pipe = &pstate->r_pipe;
+	struct dpu_sw_pipe *pipe;
+	int i;
+
+	for (i = 0; i < PIPES_PER_STAGE; i += 1) {
+		pipe = &pstate->pipe[i];
+		if (!pipe->sspp)
+			continue;
 
-	trace_dpu_plane_disable(DRMID(plane), false,
-				pstate->pipe.multirect_mode);
+		trace_dpu_plane_disable(DRMID(plane), false,
+					pstate->pipe[i].multirect_mode);
 
-	if (r_pipe->sspp) {
-		r_pipe->multirect_index = DPU_SSPP_RECT_SOLO;
-		r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
+		if (i % PIPES_PER_STAGE == 0)
+			continue;
 
-		if (r_pipe->sspp->ops.setup_multirect)
-			r_pipe->sspp->ops.setup_multirect(r_pipe);
+		/*
+		 * clear multirect for the right pipe so that the SSPP
+		 * can be further reused in the solo mode
+		 */
+		pipe->multirect_index = DPU_SSPP_RECT_SOLO;
+		pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
+		if (pipe->sspp->ops.setup_multirect)
+			pipe->sspp->ops.setup_multirect(pipe);
 	}
 
 	pstate->pending = true;
@@ -1595,31 +1613,26 @@ static void dpu_plane_atomic_print_state(struct drm_printer *p,
 		const struct drm_plane_state *state)
 {
 	const struct dpu_plane_state *pstate = to_dpu_plane_state(state);
-	const struct dpu_sw_pipe *pipe = &pstate->pipe;
-	const struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg;
-	const struct dpu_sw_pipe *r_pipe = &pstate->r_pipe;
-	const struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg;
+	const struct dpu_sw_pipe *pipe;
+	const struct dpu_sw_pipe_cfg *pipe_cfg;
+	int i;
 
 	drm_printf(p, "\tstage=%d\n", pstate->stage);
 
-	if (pipe->sspp) {
-		drm_printf(p, "\tsspp[0]=%s\n", pipe->sspp->cap->name);
-		drm_printf(p, "\tmultirect_mode[0]=%s\n",
+	for (i = 0; i < PIPES_PER_STAGE; i++) {
+		pipe = &pstate->pipe[i];
+		if (!pipe->sspp)
+			continue;
+		pipe_cfg = &pstate->pipe_cfg[i];
+		drm_printf(p, "\tsspp[%d]=%s\n", i, pipe->sspp->cap->name);
+		drm_printf(p, "\tmultirect_mode[%d]=%s\n", i,
 			   dpu_get_multirect_mode(pipe->multirect_mode));
-		drm_printf(p, "\tmultirect_index[0]=%s\n",
+		drm_printf(p, "\tmultirect_index[%d]=%s\n", i,
 			   dpu_get_multirect_index(pipe->multirect_index));
-		drm_printf(p, "\tsrc[0]=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&pipe_cfg->src_rect));
-		drm_printf(p, "\tdst[0]=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&pipe_cfg->dst_rect));
-	}
-
-	if (r_pipe->sspp) {
-		drm_printf(p, "\tsspp[1]=%s\n", r_pipe->sspp->cap->name);
-		drm_printf(p, "\tmultirect_mode[1]=%s\n",
-			   dpu_get_multirect_mode(r_pipe->multirect_mode));
-		drm_printf(p, "\tmultirect_index[1]=%s\n",
-			   dpu_get_multirect_index(r_pipe->multirect_index));
-		drm_printf(p, "\tsrc[1]=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&r_pipe_cfg->src_rect));
-		drm_printf(p, "\tdst[1]=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&r_pipe_cfg->dst_rect));
+		drm_printf(p, "\tsrc[%d]=" DRM_RECT_FMT "\n", i,
+			   DRM_RECT_ARG(&pipe_cfg->src_rect));
+		drm_printf(p, "\tdst[%d]=" DRM_RECT_FMT "\n", i,
+			   DRM_RECT_ARG(&pipe_cfg->dst_rect));
 	}
 }
 
@@ -1657,14 +1670,17 @@ void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable)
 	struct dpu_plane *pdpu = to_dpu_plane(plane);
 	struct dpu_plane_state *pstate = to_dpu_plane_state(plane->state);
 	struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);
+	int i;
 
 	if (!pdpu->is_rt_pipe)
 		return;
 
 	pm_runtime_get_sync(&dpu_kms->pdev->dev);
-	_dpu_plane_set_qos_ctrl(plane, &pstate->pipe, enable);
-	if (pstate->r_pipe.sspp)
-		_dpu_plane_set_qos_ctrl(plane, &pstate->r_pipe, enable);
+	for (i = 0; i < PIPES_PER_STAGE; i++) {
+		if (!pstate->pipe[i].sspp)
+			continue;
+		_dpu_plane_set_qos_ctrl(plane, &pstate->pipe[i], enable);
+	}
 	pm_runtime_put_sync(&dpu_kms->pdev->dev);
 }
 #endif
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
index a3a6e9028333052cbaa92830c68e2315c664c239..007f044499b99ac9c2e4b58e98e6add013a986de 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
@@ -17,10 +17,8 @@
 /**
  * struct dpu_plane_state: Define dpu extension of drm plane state object
  * @base:	base drm plane state object
- * @pipe:	software pipe description
- * @r_pipe:	software pipe description of the second pipe
- * @pipe_cfg:	software pipe configuration
- * @r_pipe_cfg:	software pipe configuration for the second pipe
+ * @pipe:	software pipe description array
+ * @pipe_cfg:	software pipe configuration array
  * @stage:	assigned by crtc blender
  * @needs_qos_remap: qos remap settings need to be updated
  * @multirect_index: index of the rectangle of SSPP
@@ -33,10 +31,8 @@
  */
 struct dpu_plane_state {
 	struct drm_plane_state base;
-	struct dpu_sw_pipe pipe;
-	struct dpu_sw_pipe r_pipe;
-	struct dpu_sw_pipe_cfg pipe_cfg;
-	struct dpu_sw_pipe_cfg r_pipe_cfg;
+	struct dpu_sw_pipe pipe[PIPES_PER_STAGE];
+	struct dpu_sw_pipe_cfg pipe_cfg[PIPES_PER_STAGE];
 	enum dpu_stage stage;
 	bool needs_qos_remap;
 	bool pending;

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v16 05/10] drm/msm/dpu: split PIPES_PER_STAGE definition per plane and mixer
  2025-09-18 13:28 [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface Jun Nie
                   ` (3 preceding siblings ...)
  2025-09-18 13:28 ` [PATCH v16 04/10] drm/msm/dpu: handle pipes as array Jun Nie
@ 2025-09-18 13:28 ` Jun Nie
  2025-09-18 13:28 ` [PATCH v16 06/10] drm/msm/dpu: Use dedicated WB number definition Jun Nie
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 28+ messages in thread
From: Jun Nie @ 2025-09-18 13:28 UTC (permalink / raw)
  To: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, Jessica Zhang
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jun Nie,
	Jessica Zhang, Dmitry Baryshkov

The stage contains configuration for a mixer pair. Currently the plane
supports just one stage and 2 pipes. Quad-pipe support will require
handling 2 stages and 4 pipes at the same time. In preparation for that
add a separate define, PIPES_PER_PLANE, to denote number of pipes that
can be used by the plane.

Signed-off-by: Jun Nie <jun.nie@linaro.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Jessica Zhang <quic_jesszhan@quicinc.com>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c    |  7 +++----
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h |  1 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c   | 19 +++++++++----------
 drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h   |  4 ++--
 4 files changed, 15 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index c69b63f858329f60908fa7544fb2e5b3aba88540..7b57e638def60f02116325401a8341da11d58e50 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -472,8 +472,7 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
 		if (pstate->stage == DPU_STAGE_BASE && format->alpha_enable)
 			bg_alpha_enable = true;
 
-
-		for (i = 0; i < PIPES_PER_STAGE; i++) {
+		for (i = 0; i < PIPES_PER_PLANE; i++) {
 			if (!pstate->pipe[i].sspp)
 				continue;
 			set_bit(pstate->pipe[i].sspp->idx, active_fetch);
@@ -1305,7 +1304,7 @@ static int dpu_crtc_reassign_planes(struct drm_crtc *crtc, struct drm_crtc_state
 	return ret;
 }
 
-#define MAX_CHANNELS_PER_CRTC 2
+#define MAX_CHANNELS_PER_CRTC PIPES_PER_PLANE
 #define MAX_HDISPLAY_SPLIT 1080
 
 static struct msm_display_topology dpu_crtc_get_topology(
@@ -1675,7 +1674,7 @@ static int _dpu_debugfs_status_show(struct seq_file *s, void *data)
 			state->crtc_x, state->crtc_y, state->crtc_w,
 			state->crtc_h);
 
-		for (i = 0; i < PIPES_PER_STAGE; i++) {
+		for (i = 0; i < PIPES_PER_PLANE; i++) {
 			if (!pstate->pipe[i].sspp)
 				continue;
 			seq_printf(s, "\tsspp[%d]:%s\n",
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
index 175639c8bfbb9bbd02ed35f1780bcbd869f08c36..9f75b497aa0c939296207d58dde32028d0a76a6d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
@@ -34,6 +34,7 @@
 #define DPU_MAX_PLANES			4
 #endif
 
+#define PIPES_PER_PLANE			2
 #define PIPES_PER_STAGE			2
 #ifndef DPU_MAX_DE_CURVES
 #define DPU_MAX_DE_CURVES		3
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index 5bcdfe7078f717a59dc5a4883702d921ecf2025b..0be3eeb5edf0c14efb20eec02ba17e072fa2c829 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -634,7 +634,7 @@ static void _dpu_plane_color_fill(struct dpu_plane *pdpu,
 		return;
 
 	/* update sspp */
-	for (i = 0; i < PIPES_PER_STAGE; i++) {
+	for (i = 0; i < PIPES_PER_PLANE; i++) {
 		if (!pstate->pipe[i].sspp)
 			continue;
 		_dpu_plane_color_fill_pipe(pstate, &pstate->pipe[i],
@@ -1157,7 +1157,7 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
 		 * resources are freed by dpu_crtc_assign_plane_resources(),
 		 * but clean them here.
 		 */
-		for (i = 0; i < PIPES_PER_STAGE; i++)
+		for (i = 0; i < PIPES_PER_PLANE; i++)
 			pstate->pipe[i].sspp = NULL;
 
 		return 0;
@@ -1211,7 +1211,7 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
 	pipe_cfg = &pstate->pipe_cfg[0];
 	r_pipe_cfg = &pstate->pipe_cfg[1];
 
-	for (i = 0; i < PIPES_PER_STAGE; i++)
+	for (i = 0; i < PIPES_PER_PLANE; i++)
 		pstate->pipe[i].sspp = NULL;
 
 	if (!plane_state->fb)
@@ -1344,7 +1344,7 @@ void dpu_plane_flush(struct drm_plane *plane)
 		/* force 100% alpha */
 		_dpu_plane_color_fill(pdpu, pdpu->color_fill, 0xFF);
 	else {
-		for (i = 0; i < PIPES_PER_STAGE; i++)
+		for (i = 0; i < PIPES_PER_PLANE; i++)
 			dpu_plane_flush_csc(pdpu, &pstate->pipe[i]);
 	}
 
@@ -1466,8 +1466,7 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane,
 			crtc->base.id, DRM_RECT_ARG(&state->dst),
 			&fmt->pixel_format, MSM_FORMAT_IS_UBWC(fmt));
 
-	/* move the assignment here, to ease handling to another pairs later */
-	for (i = 0; i < PIPES_PER_STAGE; i++) {
+	for (i = 0; i < PIPES_PER_PLANE; i++) {
 		if (!drm_rect_width(&pstate->pipe_cfg[i].src_rect))
 			continue;
 		dpu_plane_sspp_update_pipe(plane, &pstate->pipe[i],
@@ -1481,7 +1480,7 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane,
 
 	pstate->plane_fetch_bw = 0;
 	pstate->plane_clk = 0;
-	for (i = 0; i < PIPES_PER_STAGE; i++) {
+	for (i = 0; i < PIPES_PER_PLANE; i++) {
 		if (!drm_rect_width(&pstate->pipe_cfg[i].src_rect))
 			continue;
 		pstate->plane_fetch_bw += _dpu_plane_calc_bw(pdpu->catalog, fmt,
@@ -1500,7 +1499,7 @@ static void _dpu_plane_atomic_disable(struct drm_plane *plane)
 	struct dpu_sw_pipe *pipe;
 	int i;
 
-	for (i = 0; i < PIPES_PER_STAGE; i += 1) {
+	for (i = 0; i < PIPES_PER_PLANE; i += 1) {
 		pipe = &pstate->pipe[i];
 		if (!pipe->sspp)
 			continue;
@@ -1619,7 +1618,7 @@ static void dpu_plane_atomic_print_state(struct drm_printer *p,
 
 	drm_printf(p, "\tstage=%d\n", pstate->stage);
 
-	for (i = 0; i < PIPES_PER_STAGE; i++) {
+	for (i = 0; i < PIPES_PER_PLANE; i++) {
 		pipe = &pstate->pipe[i];
 		if (!pipe->sspp)
 			continue;
@@ -1676,7 +1675,7 @@ void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable)
 		return;
 
 	pm_runtime_get_sync(&dpu_kms->pdev->dev);
-	for (i = 0; i < PIPES_PER_STAGE; i++) {
+	for (i = 0; i < PIPES_PER_PLANE; i++) {
 		if (!pstate->pipe[i].sspp)
 			continue;
 		_dpu_plane_set_qos_ctrl(plane, &pstate->pipe[i], enable);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
index 007f044499b99ac9c2e4b58e98e6add013a986de..1ef5a041b8acae270826f20ea9553cbfa35a9f82 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
@@ -31,8 +31,8 @@
  */
 struct dpu_plane_state {
 	struct drm_plane_state base;
-	struct dpu_sw_pipe pipe[PIPES_PER_STAGE];
-	struct dpu_sw_pipe_cfg pipe_cfg[PIPES_PER_STAGE];
+	struct dpu_sw_pipe pipe[PIPES_PER_PLANE];
+	struct dpu_sw_pipe_cfg pipe_cfg[PIPES_PER_PLANE];
 	enum dpu_stage stage;
 	bool needs_qos_remap;
 	bool pending;

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v16 06/10] drm/msm/dpu: Use dedicated WB number definition
  2025-09-18 13:28 [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface Jun Nie
                   ` (4 preceding siblings ...)
  2025-09-18 13:28 ` [PATCH v16 05/10] drm/msm/dpu: split PIPES_PER_STAGE definition per plane and mixer Jun Nie
@ 2025-09-18 13:28 ` Jun Nie
  2025-09-18 13:28 ` [PATCH v16 07/10] drm/msm/dpu: blend pipes per mixer pairs config Jun Nie
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 28+ messages in thread
From: Jun Nie @ 2025-09-18 13:28 UTC (permalink / raw)
  To: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, Jessica Zhang
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jun Nie,
	Jessica Zhang, Dmitry Baryshkov

Currently MAX_CHANNELS_PER_ENC is defined as 2, because 2 channels are
supported at most in one encoder. The case of 4 channels per encoder is
to be added. To avoid breaking current WB usage case, use dedicated WB
definition before 4 WB usage case is supported in future.

Signed-off-by: Jun Nie <jun.nie@linaro.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Jessica Zhang <quic_jesszhan@quicinc.com>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 1318f9e63ef1e7bab078ae17e39d9ed19c04f465..55b83ba6102d38a9ec97bc4d12ad31810e4b261a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -56,6 +56,7 @@
 	(MAX_H_TILES_PER_DISPLAY * NUM_PHYS_ENCODER_TYPES)
 
 #define MAX_CHANNELS_PER_ENC 2
+#define MAX_CWB_PER_ENC 2
 
 #define IDLE_SHORT_TIMEOUT	1
 
@@ -182,7 +183,7 @@ struct dpu_encoder_virt {
 	struct dpu_encoder_phys *cur_master;
 	struct dpu_encoder_phys *cur_slave;
 	struct dpu_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
-	struct dpu_hw_cwb *hw_cwb[MAX_CHANNELS_PER_ENC];
+	struct dpu_hw_cwb *hw_cwb[MAX_CWB_PER_ENC];
 	struct dpu_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC];
 
 	unsigned int dsc_mask;
@@ -2389,7 +2390,7 @@ void dpu_encoder_helper_phys_setup_cwb(struct dpu_encoder_phys *phys_enc,
 	 */
 	cwb_cfg.input = INPUT_MODE_LM_OUT;
 
-	for (int i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
+	for (int i = 0; i < MAX_CWB_PER_ENC; i++) {
 		hw_cwb = dpu_enc->hw_cwb[i];
 		if (!hw_cwb)
 			continue;

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v16 07/10] drm/msm/dpu: blend pipes per mixer pairs config
  2025-09-18 13:28 [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface Jun Nie
                   ` (5 preceding siblings ...)
  2025-09-18 13:28 ` [PATCH v16 06/10] drm/msm/dpu: Use dedicated WB number definition Jun Nie
@ 2025-09-18 13:28 ` Jun Nie
  2025-09-18 13:29 ` [PATCH v16 08/10] drm/msm/dpu: support SSPP assignment for quad-pipe case Jun Nie
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 28+ messages in thread
From: Jun Nie @ 2025-09-18 13:28 UTC (permalink / raw)
  To: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, Jessica Zhang
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jun Nie,
	Jessica Zhang, Dmitry Baryshkov

Currently, only 2 pipes are used at most for a plane. A stage structure
describes the configuration for a mixer pair. So only one stage is needed
for current usage cases. The quad-pipe case will be added in future and 2
stages are used in the case. So extend the stage to an array with array
size STAGES_PER_PLANE and blend pipes per mixer pair with configuration in
the stage structure.

Signed-off-by: Jun Nie <jun.nie@linaro.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Jessica Zhang <quic_jesszhan@quicinc.com>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c    | 49 ++++++++++++++++++-----------
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h |  3 +-
 2 files changed, 33 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 7b57e638def60f02116325401a8341da11d58e50..d825eb8e40ae8bd456ede6269951339e3053d0d3 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -400,7 +400,7 @@ static void _dpu_crtc_program_lm_output_roi(struct drm_crtc *crtc)
 static void _dpu_crtc_blend_setup_pipe(struct drm_crtc *crtc,
 				       struct drm_plane *plane,
 				       struct dpu_crtc_mixer *mixer,
-				       u32 num_mixers,
+				       u32 lms_in_pair,
 				       enum dpu_stage stage,
 				       const struct msm_format *format,
 				       uint64_t modifier,
@@ -434,7 +434,7 @@ static void _dpu_crtc_blend_setup_pipe(struct drm_crtc *crtc,
 	stage_cfg->multirect_index[stage][stage_idx] = pipe->multirect_index;
 
 	/* blend config update */
-	for (lm_idx = 0; lm_idx < num_mixers; lm_idx++)
+	for (lm_idx = 0; lm_idx < lms_in_pair; lm_idx++)
 		mixer[lm_idx].lm_ctl->ops.update_pending_flush_sspp(mixer[lm_idx].lm_ctl, sspp_idx);
 }
 
@@ -449,7 +449,7 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
 	struct dpu_plane_state *pstate = NULL;
 	const struct msm_format *format;
 	struct dpu_hw_ctl *ctl = mixer->lm_ctl;
-	u32 lm_idx, i;
+	u32 lm_idx, stage, i, pipe_idx, head_pipe_in_stage, lms_in_pair;
 	bool bg_alpha_enable = false;
 	DECLARE_BITMAP(active_fetch, SSPP_MAX);
 	DECLARE_BITMAP(active_pipes, SSPP_MAX);
@@ -472,16 +472,25 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
 		if (pstate->stage == DPU_STAGE_BASE && format->alpha_enable)
 			bg_alpha_enable = true;
 
-		for (i = 0; i < PIPES_PER_PLANE; i++) {
-			if (!pstate->pipe[i].sspp)
-				continue;
-			set_bit(pstate->pipe[i].sspp->idx, active_fetch);
-			set_bit(pstate->pipe[i].sspp->idx, active_pipes);
-			_dpu_crtc_blend_setup_pipe(crtc, plane,
-						   mixer, cstate->num_mixers,
-						   pstate->stage,
-						   format, fb ? fb->modifier : 0,
-						   &pstate->pipe[i], i, stage_cfg);
+		/* loop pipe per mixer pair with config in stage structure */
+		for (stage = 0; stage < STAGES_PER_PLANE; stage++) {
+			head_pipe_in_stage = stage * PIPES_PER_STAGE;
+			for (i = 0; i < PIPES_PER_STAGE; i++) {
+				pipe_idx = i + head_pipe_in_stage;
+				if (!pstate->pipe[pipe_idx].sspp)
+					continue;
+				lms_in_pair = min(cstate->num_mixers - (stage * PIPES_PER_STAGE),
+						  PIPES_PER_STAGE);
+				set_bit(pstate->pipe[pipe_idx].sspp->idx, active_fetch);
+				set_bit(pstate->pipe[pipe_idx].sspp->idx, active_pipes);
+				_dpu_crtc_blend_setup_pipe(crtc, plane,
+							   &mixer[head_pipe_in_stage],
+							   lms_in_pair,
+							   pstate->stage,
+							   format, fb ? fb->modifier : 0,
+							   &pstate->pipe[pipe_idx], i,
+							   &stage_cfg[stage]);
+			}
 		}
 
 		/* blend config update */
@@ -517,7 +526,7 @@ static void _dpu_crtc_blend_setup(struct drm_crtc *crtc)
 	struct dpu_crtc_mixer *mixer = cstate->mixers;
 	struct dpu_hw_ctl *ctl;
 	struct dpu_hw_mixer *lm;
-	struct dpu_hw_stage_cfg stage_cfg;
+	struct dpu_hw_stage_cfg stage_cfg[STAGES_PER_PLANE];
 	DECLARE_BITMAP(active_lms, LM_MAX);
 	int i;
 
@@ -538,10 +547,10 @@ static void _dpu_crtc_blend_setup(struct drm_crtc *crtc)
 	}
 
 	/* initialize stage cfg */
-	memset(&stage_cfg, 0, sizeof(struct dpu_hw_stage_cfg));
+	memset(&stage_cfg, 0, sizeof(stage_cfg));
 	memset(active_lms, 0, sizeof(active_lms));
 
-	_dpu_crtc_blend_setup_mixer(crtc, dpu_crtc, mixer, &stage_cfg);
+	_dpu_crtc_blend_setup_mixer(crtc, dpu_crtc, mixer, stage_cfg);
 
 	for (i = 0; i < cstate->num_mixers; i++) {
 		ctl = mixer[i].lm_ctl;
@@ -562,13 +571,17 @@ static void _dpu_crtc_blend_setup(struct drm_crtc *crtc)
 			mixer[i].mixer_op_mode,
 			ctl->idx - CTL_0);
 
+		/*
+		 * call dpu_hw_ctl_setup_blendstage() to blend layers per stage cfg.
+		 * stage data is shared between PIPES_PER_STAGE pipes.
+		 */
 		if (ctl->ops.setup_blendstage)
 			ctl->ops.setup_blendstage(ctl, mixer[i].hw_lm->idx,
-						  &stage_cfg);
+				&stage_cfg[i / PIPES_PER_STAGE]);
 
 		if (lm->ops.setup_blendstage)
 			lm->ops.setup_blendstage(lm, mixer[i].hw_lm->idx,
-						 &stage_cfg);
+				&stage_cfg[i / PIPES_PER_STAGE]);
 	}
 }
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
index 9f75b497aa0c939296207d58dde32028d0a76a6d..e4875a1f638db6f1983d9c51cb399319d27675e9 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
@@ -34,8 +34,9 @@
 #define DPU_MAX_PLANES			4
 #endif
 
-#define PIPES_PER_PLANE			2
+#define STAGES_PER_PLANE		1
 #define PIPES_PER_STAGE			2
+#define PIPES_PER_PLANE			(PIPES_PER_STAGE * STAGES_PER_PLANE)
 #ifndef DPU_MAX_DE_CURVES
 #define DPU_MAX_DE_CURVES		3
 #endif

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v16 08/10] drm/msm/dpu: support SSPP assignment for quad-pipe case
  2025-09-18 13:28 [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface Jun Nie
                   ` (6 preceding siblings ...)
  2025-09-18 13:28 ` [PATCH v16 07/10] drm/msm/dpu: blend pipes per mixer pairs config Jun Nie
@ 2025-09-18 13:29 ` Jun Nie
  2025-09-18 13:29 ` [PATCH v16 09/10] drm/msm/dpu: support plane splitting in " Jun Nie
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 28+ messages in thread
From: Jun Nie @ 2025-09-18 13:29 UTC (permalink / raw)
  To: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, Jessica Zhang
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jun Nie,
	Dmitry Baryshkov

Currently, SSPPs are assigned to a maximum of two pipes. However,
quad-pipe usage scenarios require four pipes and involve configuring
two stages. In quad-pipe case, the first two pipes share a set of
mixer configurations and enable multi-rect mode when certain
conditions are met. The same applies to the subsequent two pipes.

Assign SSPPs to the pipes in each stage using a unified method and
to loop the stages accordingly.

Signed-off-by: Jun Nie <jun.nie@linaro.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Jessica Zhang <jessica.zhang@oss.qualcomm.com>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 150 ++++++++++++++++++------------
 1 file changed, 89 insertions(+), 61 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index 0be3eeb5edf0c14efb20eec02ba17e072fa2c829..5ae58352cbee1251a0140879f04fc7c304cae674 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -957,6 +957,23 @@ static int dpu_plane_is_multirect_parallel_capable(struct dpu_hw_sspp *sspp,
 		dpu_plane_is_parallel_capable(pipe_cfg, fmt, max_linewidth);
 }
 
+static bool dpu_plane_get_single_pipe_in_stage(struct dpu_plane_state *pstate,
+					       struct dpu_sw_pipe **single_pipe,
+					       struct dpu_sw_pipe_cfg **single_pipe_cfg,
+					       int stage_index)
+{
+	int pipe_idx;
+
+	pipe_idx = stage_index * PIPES_PER_STAGE;
+	if (drm_rect_width(&pstate->pipe_cfg[pipe_idx].src_rect) != 0 &&
+	    drm_rect_width(&pstate->pipe_cfg[pipe_idx + 1].src_rect) == 0) {
+		*single_pipe = &pstate->pipe[pipe_idx];
+		*single_pipe_cfg = &pstate->pipe_cfg[pipe_idx];
+		return true;
+	}
+
+	return false;
+}
 
 static int dpu_plane_atomic_check_sspp(struct drm_plane *plane,
 				       struct drm_atomic_state *state,
@@ -1022,17 +1039,20 @@ static bool dpu_plane_try_multirect_parallel(struct dpu_sw_pipe *pipe, struct dp
 static int dpu_plane_try_multirect_shared(struct dpu_plane_state *pstate,
 					  struct dpu_plane_state *prev_adjacent_pstate,
 					  const struct msm_format *fmt,
-					  uint32_t max_linewidth)
+					  uint32_t max_linewidth, int stage_index)
 {
-	struct dpu_sw_pipe *pipe = &pstate->pipe[0];
-	struct dpu_sw_pipe *r_pipe = &pstate->pipe[1];
-	struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg[0];
-	struct dpu_sw_pipe *prev_pipe = &prev_adjacent_pstate->pipe[0];
-	struct dpu_sw_pipe_cfg *prev_pipe_cfg = &prev_adjacent_pstate->pipe_cfg[0];
+	struct dpu_sw_pipe *pipe, *prev_pipe;
+	struct dpu_sw_pipe_cfg *pipe_cfg, *prev_pipe_cfg;
 	const struct msm_format *prev_fmt = msm_framebuffer_format(prev_adjacent_pstate->base.fb);
 	u16 max_tile_height = 1;
 
-	if (prev_adjacent_pstate->pipe[1].sspp != NULL ||
+	if (!dpu_plane_get_single_pipe_in_stage(pstate, &pipe,
+						&pipe_cfg, stage_index))
+		return false;
+
+	if (!dpu_plane_get_single_pipe_in_stage(prev_adjacent_pstate,
+						&prev_pipe, &prev_pipe_cfg,
+						stage_index) ||
 	    prev_pipe->multirect_mode != DPU_SSPP_MULTIRECT_NONE)
 		return false;
 
@@ -1047,11 +1067,6 @@ static int dpu_plane_try_multirect_shared(struct dpu_plane_state *pstate,
 	if (MSM_FORMAT_IS_UBWC(prev_fmt))
 		max_tile_height = max(max_tile_height, prev_fmt->tile_height);
 
-	r_pipe->multirect_index = DPU_SSPP_RECT_SOLO;
-	r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
-
-	r_pipe->sspp = NULL;
-
 	if (dpu_plane_is_parallel_capable(pipe_cfg, fmt, max_linewidth) &&
 	    dpu_plane_is_parallel_capable(prev_pipe_cfg, prev_fmt, max_linewidth) &&
 	    (pipe_cfg->dst_rect.x1 >= prev_pipe_cfg->dst_rect.x2 ||
@@ -1180,36 +1195,69 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
 	return 0;
 }
 
+static int dpu_plane_assign_resource_in_stage(struct dpu_sw_pipe *pipe,
+					      struct dpu_sw_pipe_cfg *pipe_cfg,
+					      struct drm_plane_state *plane_state,
+					      struct dpu_global_state *global_state,
+					      struct drm_crtc *crtc,
+					      struct dpu_rm_sspp_requirements *reqs)
+{
+	struct drm_plane *plane = plane_state->plane;
+	struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);
+	struct dpu_sw_pipe *r_pipe = pipe + 1;
+	struct dpu_sw_pipe_cfg *r_pipe_cfg = pipe_cfg + 1;
+
+	if (drm_rect_width(&pipe_cfg->src_rect) == 0)
+		return 0;
+
+	pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, reqs);
+	if (!pipe->sspp)
+		return -ENODEV;
+	pipe->multirect_index = DPU_SSPP_RECT_SOLO;
+	pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
+
+	if (drm_rect_width(&r_pipe_cfg->src_rect) == 0)
+		return 0;
+
+	if (dpu_plane_try_multirect_parallel(pipe, pipe_cfg, r_pipe, r_pipe_cfg,
+					      pipe->sspp,
+					      msm_framebuffer_format(plane_state->fb),
+					      dpu_kms->catalog->caps->max_linewidth))
+		return 0;
+
+	r_pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, reqs);
+	if (!r_pipe->sspp)
+		return -ENODEV;
+	r_pipe->multirect_index = DPU_SSPP_RECT_SOLO;
+	r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
+
+	return 0;
+}
+
 static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
 					      struct dpu_global_state *global_state,
 					      struct drm_atomic_state *state,
 					      struct drm_plane_state *plane_state,
-					      struct drm_plane_state *prev_adjacent_plane_state)
+					      struct drm_plane_state **prev_adjacent_plane_state)
 {
 	const struct drm_crtc_state *crtc_state = NULL;
 	struct drm_plane *plane = plane_state->plane;
 	struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);
 	struct dpu_rm_sspp_requirements reqs;
-	struct dpu_plane_state *pstate, *prev_adjacent_pstate;
+	struct dpu_plane_state *pstate, *prev_adjacent_pstate[STAGES_PER_PLANE];
 	struct dpu_sw_pipe *pipe;
-	struct dpu_sw_pipe *r_pipe;
 	struct dpu_sw_pipe_cfg *pipe_cfg;
-	struct dpu_sw_pipe_cfg *r_pipe_cfg;
 	const struct msm_format *fmt;
-	int i;
+	int i, ret;
 
 	if (plane_state->crtc)
 		crtc_state = drm_atomic_get_new_crtc_state(state,
 							   plane_state->crtc);
 
 	pstate = to_dpu_plane_state(plane_state);
-	prev_adjacent_pstate = prev_adjacent_plane_state ?
-		to_dpu_plane_state(prev_adjacent_plane_state) : NULL;
-
-	pipe = &pstate->pipe[0];
-	r_pipe = &pstate->pipe[1];
-	pipe_cfg = &pstate->pipe_cfg[0];
-	r_pipe_cfg = &pstate->pipe_cfg[1];
+	for (i = 0; i < STAGES_PER_PLANE; i++)
+		prev_adjacent_pstate[i] = prev_adjacent_plane_state[i] ?
+			to_dpu_plane_state(prev_adjacent_plane_state[i]) : NULL;
 
 	for (i = 0; i < PIPES_PER_PLANE; i++)
 		pstate->pipe[i].sspp = NULL;
@@ -1224,42 +1272,24 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
 
 	reqs.rot90 = drm_rotation_90_or_270(plane_state->rotation);
 
-	if (drm_rect_width(&r_pipe_cfg->src_rect) == 0) {
-		if (!prev_adjacent_pstate ||
-		    !dpu_plane_try_multirect_shared(pstate, prev_adjacent_pstate, fmt,
-						    dpu_kms->catalog->caps->max_linewidth)) {
-			pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
-			if (!pipe->sspp)
-				return -ENODEV;
-
-			r_pipe->sspp = NULL;
+	for (i = 0; i < STAGES_PER_PLANE; i++) {
+		if (prev_adjacent_pstate[i] &&
+		    dpu_plane_try_multirect_shared(pstate, prev_adjacent_pstate[i], fmt,
+						   dpu_kms->catalog->caps->max_linewidth,
+						   i))
+			continue;
 
-			pipe->multirect_index = DPU_SSPP_RECT_SOLO;
-			pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
+		if (dpu_plane_get_single_pipe_in_stage(pstate, &pipe, &pipe_cfg, i))
+			prev_adjacent_plane_state[i] = plane_state;
 
-			r_pipe->multirect_index = DPU_SSPP_RECT_SOLO;
-			r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
-		}
-	} else {
-		pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
-		if (!pipe->sspp)
-			return -ENODEV;
-
-		if (!dpu_plane_try_multirect_parallel(pipe, pipe_cfg, r_pipe, r_pipe_cfg,
-						      pipe->sspp,
-						      msm_framebuffer_format(plane_state->fb),
-						      dpu_kms->catalog->caps->max_linewidth)) {
-			/* multirect is not possible, use two SSPP blocks */
-			r_pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
-			if (!r_pipe->sspp)
-				return -ENODEV;
-
-			pipe->multirect_index = DPU_SSPP_RECT_SOLO;
-			pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
-
-			r_pipe->multirect_index = DPU_SSPP_RECT_SOLO;
-			r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
-		}
+		pipe = &pstate->pipe[i * PIPES_PER_STAGE];
+		pipe_cfg = &pstate->pipe_cfg[i * PIPES_PER_STAGE];
+		ret = dpu_plane_assign_resource_in_stage(pipe, pipe_cfg,
+							 plane_state,
+							 global_state,
+							 crtc, &reqs);
+		if (ret)
+			return ret;
 	}
 
 	return dpu_plane_atomic_check_sspp(plane, state, crtc_state);
@@ -1272,7 +1302,7 @@ int dpu_assign_plane_resources(struct dpu_global_state *global_state,
 			       unsigned int num_planes)
 {
 	unsigned int i;
-	struct drm_plane_state *prev_adjacent_plane_state = NULL;
+	struct drm_plane_state *prev_adjacent_plane_state[STAGES_PER_PLANE] = { NULL };
 
 	for (i = 0; i < num_planes; i++) {
 		struct drm_plane_state *plane_state = states[i];
@@ -1286,8 +1316,6 @@ int dpu_assign_plane_resources(struct dpu_global_state *global_state,
 							     prev_adjacent_plane_state);
 		if (ret)
 			break;
-
-		prev_adjacent_plane_state = plane_state;
 	}
 
 	return 0;

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v16 09/10] drm/msm/dpu: support plane splitting in quad-pipe case
  2025-09-18 13:28 [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface Jun Nie
                   ` (7 preceding siblings ...)
  2025-09-18 13:29 ` [PATCH v16 08/10] drm/msm/dpu: support SSPP assignment for quad-pipe case Jun Nie
@ 2025-09-18 13:29 ` Jun Nie
  2025-12-18 12:44   ` Abel Vesa
  2026-01-14 14:48   ` Jun Nie
  2025-09-18 13:29 ` [PATCH v16 10/10] drm/msm/dpu: Enable quad-pipe for DSC and dual-DSI case Jun Nie
                   ` (2 subsequent siblings)
  11 siblings, 2 replies; 28+ messages in thread
From: Jun Nie @ 2025-09-18 13:29 UTC (permalink / raw)
  To: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, Jessica Zhang
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jun Nie,
	Dmitry Baryshkov

The content of every half of screen is sent out via one interface in
dual-DSI case. The content for every interface is blended by a LM
pair in quad-pipe case, thus a LM pair should not blend any content
that cross the half of screen in this case. Clip plane into pipes per
left and right half screen ROI if topology is quad pipe case.

The clipped rectangle on every half of screen is futher handled by two
pipes if its width exceeds a limit for a single pipe.

Signed-off-by: Jun Nie <jun.nie@linaro.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Jessica Zhang <jessica.zhang@oss.qualcomm.com>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c  |  11 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h  |   2 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 137 +++++++++++++++++++++---------
 3 files changed, 110 insertions(+), 40 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index d825eb8e40ae8bd456ede6269951339e3053d0d3..e925d93b38feac0594d735fdc2c5b9fd5ae83e6a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -1604,6 +1604,17 @@ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en)
 	return 0;
 }
 
+/**
+ * dpu_crtc_get_num_lm - Get mixer number in this CRTC pipeline
+ * @state: Pointer to drm crtc state object
+ */
+unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state)
+{
+	struct dpu_crtc_state *cstate = to_dpu_crtc_state(state);
+
+	return cstate->num_mixers;
+}
+
 #ifdef CONFIG_DEBUG_FS
 static int _dpu_debugfs_status_show(struct seq_file *s, void *data)
 {
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
index 94392b9b924546f96e738ae20920cf9afd568e6b..6eaba5696e8e6bd1246a9895c4c8714ca6589b10 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
@@ -267,4 +267,6 @@ static inline enum dpu_crtc_client_type dpu_crtc_get_client_type(
 
 void dpu_crtc_frame_event_cb(struct drm_crtc *crtc, u32 event);
 
+unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state);
+
 #endif /* _DPU_CRTC_H_ */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index 5ae58352cbee1251a0140879f04fc7c304cae674..89a5feb6308bcac537562c3dc4e61c16c92e460c 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -824,8 +824,12 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
 	struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state);
 	struct dpu_sw_pipe_cfg *pipe_cfg;
 	struct dpu_sw_pipe_cfg *r_pipe_cfg;
+	struct dpu_sw_pipe_cfg init_pipe_cfg;
 	struct drm_rect fb_rect = { 0 };
+	const struct drm_display_mode *mode = &crtc_state->adjusted_mode;
 	uint32_t max_linewidth;
+	u32 num_lm;
+	int stage_id, num_stages;
 
 	min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
 	max_scale = MAX_DOWNSCALE_RATIO << 16;
@@ -848,13 +852,10 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
 		return -EINVAL;
 	}
 
-	/* move the assignment here, to ease handling to another pairs later */
-	pipe_cfg = &pstate->pipe_cfg[0];
-	r_pipe_cfg = &pstate->pipe_cfg[1];
-	/* state->src is 16.16, src_rect is not */
-	drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src);
+	num_lm = dpu_crtc_get_num_lm(crtc_state);
 
-	pipe_cfg->dst_rect = new_plane_state->dst;
+	/* state->src is 16.16, src_rect is not */
+	drm_rect_fp_to_int(&init_pipe_cfg.src_rect, &new_plane_state->src);
 
 	fb_rect.x2 = new_plane_state->fb->width;
 	fb_rect.y2 = new_plane_state->fb->height;
@@ -879,35 +880,94 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
 
 	max_linewidth = pdpu->catalog->caps->max_linewidth;
 
-	drm_rect_rotate(&pipe_cfg->src_rect,
+	drm_rect_rotate(&init_pipe_cfg.src_rect,
 			new_plane_state->fb->width, new_plane_state->fb->height,
 			new_plane_state->rotation);
 
-	if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) ||
-	     _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) {
-		if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) {
-			DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n",
-					DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);
-			return -E2BIG;
+	/*
+	 * We have 1 mixer pair cfg for 1:1:1 and 2:2:1 topology, 2 mixer pair
+	 * configs for left and right half screen in case of 4:4:2 topology.
+	 * But we may have 2 rect to split wide plane that exceeds limit with 1
+	 * config for 2:2:1. So need to handle both wide plane splitting, and
+	 * two halves of screen splitting for quad-pipe case. Check dest
+	 * rectangle left/right clipping first, then check wide rectangle
+	 * splitting in every half next.
+	 */
+	num_stages = (num_lm + 1) / 2;
+	/* iterate mixer configs for this plane, to separate left/right with the id */
+	for (stage_id = 0; stage_id < num_stages; stage_id++) {
+		struct drm_rect mixer_rect = {
+			.x1 = stage_id * mode->hdisplay / num_stages,
+			.y1 = 0,
+			.x2 = (stage_id + 1) * mode->hdisplay / num_stages,
+			.y2 = mode->vdisplay
+			};
+		int cfg_idx = stage_id * PIPES_PER_STAGE;
+
+		pipe_cfg = &pstate->pipe_cfg[cfg_idx];
+		r_pipe_cfg = &pstate->pipe_cfg[cfg_idx + 1];
+
+		drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src);
+		pipe_cfg->dst_rect = new_plane_state->dst;
+
+		DPU_DEBUG_PLANE(pdpu, "checking src " DRM_RECT_FMT
+				" vs clip window " DRM_RECT_FMT "\n",
+				DRM_RECT_ARG(&pipe_cfg->src_rect),
+				DRM_RECT_ARG(&mixer_rect));
+
+		/*
+		 * If this plane does not fall into mixer rect, check next
+		 * mixer rect.
+		 */
+		if (!drm_rect_clip_scaled(&pipe_cfg->src_rect,
+					  &pipe_cfg->dst_rect,
+					  &mixer_rect)) {
+			memset(pipe_cfg, 0, 2 * sizeof(struct dpu_sw_pipe_cfg));
+
+			continue;
 		}
 
-		*r_pipe_cfg = *pipe_cfg;
-		pipe_cfg->src_rect.x2 = (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2) >> 1;
-		pipe_cfg->dst_rect.x2 = (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2) >> 1;
-		r_pipe_cfg->src_rect.x1 = pipe_cfg->src_rect.x2;
-		r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2;
-	} else {
-		memset(r_pipe_cfg, 0, sizeof(*r_pipe_cfg));
-	}
+		pipe_cfg->dst_rect.x1 -= mixer_rect.x1;
+		pipe_cfg->dst_rect.x2 -= mixer_rect.x1;
+
+		DPU_DEBUG_PLANE(pdpu, "Got clip src:" DRM_RECT_FMT " dst: " DRM_RECT_FMT "\n",
+				DRM_RECT_ARG(&pipe_cfg->src_rect), DRM_RECT_ARG(&pipe_cfg->dst_rect));
+
+		/* Split wide rect into 2 rect */
+		if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) ||
+		     _dpu_plane_calc_clk(mode, pipe_cfg) > max_mdp_clk_rate) {
+
+			if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) {
+				DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n",
+						DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);
+				return -E2BIG;
+			}
+
+			memcpy(r_pipe_cfg, pipe_cfg, sizeof(struct dpu_sw_pipe_cfg));
+			pipe_cfg->src_rect.x2 = (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2) >> 1;
+			pipe_cfg->dst_rect.x2 = (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2) >> 1;
+			r_pipe_cfg->src_rect.x1 = pipe_cfg->src_rect.x2;
+			r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2;
+			DPU_DEBUG_PLANE(pdpu, "Split wide plane into:"
+					DRM_RECT_FMT " and " DRM_RECT_FMT "\n",
+					DRM_RECT_ARG(&pipe_cfg->src_rect),
+					DRM_RECT_ARG(&r_pipe_cfg->src_rect));
+		} else {
+			memset(r_pipe_cfg, 0, sizeof(struct dpu_sw_pipe_cfg));
+		}
 
-	drm_rect_rotate_inv(&pipe_cfg->src_rect,
-			    new_plane_state->fb->width, new_plane_state->fb->height,
-			    new_plane_state->rotation);
-	if (drm_rect_width(&r_pipe_cfg->src_rect) != 0)
-		drm_rect_rotate_inv(&r_pipe_cfg->src_rect,
-				    new_plane_state->fb->width, new_plane_state->fb->height,
+		drm_rect_rotate_inv(&pipe_cfg->src_rect,
+				    new_plane_state->fb->width,
+				    new_plane_state->fb->height,
 				    new_plane_state->rotation);
 
+		if (drm_rect_width(&r_pipe_cfg->src_rect) != 0)
+			drm_rect_rotate_inv(&r_pipe_cfg->src_rect,
+					    new_plane_state->fb->width,
+					    new_plane_state->fb->height,
+					    new_plane_state->rotation);
+	}
+
 	pstate->needs_qos_remap = drm_atomic_crtc_needs_modeset(crtc_state);
 
 	return 0;
@@ -983,20 +1043,17 @@ static int dpu_plane_atomic_check_sspp(struct drm_plane *plane,
 		drm_atomic_get_new_plane_state(state, plane);
 	struct dpu_plane *pdpu = to_dpu_plane(plane);
 	struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state);
-	struct dpu_sw_pipe *pipe = &pstate->pipe[0];
-	struct dpu_sw_pipe *r_pipe = &pstate->pipe[1];
-	struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg[0];
-	struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->pipe_cfg[1];
-	int ret = 0;
-
-	ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg,
-					  &crtc_state->adjusted_mode,
-					  new_plane_state);
-	if (ret)
-		return ret;
+	struct dpu_sw_pipe *pipe;
+	struct dpu_sw_pipe_cfg *pipe_cfg;
+	int ret = 0, i;
 
-	if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) {
-		ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg,
+	for (i = 0; i < PIPES_PER_PLANE; i++) {
+		pipe = &pstate->pipe[i];
+		pipe_cfg = &pstate->pipe_cfg[i];
+		if (!drm_rect_width(&pipe_cfg->src_rect))
+			continue;
+		DPU_DEBUG_PLANE(pdpu, "pipe %d is in use, validate it\n", i);
+		ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg,
 						  &crtc_state->adjusted_mode,
 						  new_plane_state);
 		if (ret)

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v16 10/10] drm/msm/dpu: Enable quad-pipe for DSC and dual-DSI case
  2025-09-18 13:28 [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface Jun Nie
                   ` (8 preceding siblings ...)
  2025-09-18 13:29 ` [PATCH v16 09/10] drm/msm/dpu: support plane splitting in " Jun Nie
@ 2025-09-18 13:29 ` Jun Nie
  2025-09-19 16:57   ` Dmitry Baryshkov
  2025-11-29 16:37   ` Marijn Suijten
  2025-09-19  0:41 ` [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface Dmitry Baryshkov
  2025-11-14 14:26 ` Dmitry Baryshkov
  11 siblings, 2 replies; 28+ messages in thread
From: Jun Nie @ 2025-09-18 13:29 UTC (permalink / raw)
  To: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, Jessica Zhang
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jun Nie,
	Jessica Zhang, Dmitry Baryshkov

To support high-resolution cases that exceed the width limitation of
a pair of SSPPs, or scenarios that surpass the maximum MDP clock rate,
additional pipes are necessary to enable parallel data processing
within the SSPP width constraints and MDP clock rate.

Request 4 mixers and 4 DSCs for high-resolution cases where both DSC
and dual interfaces are enabled. More use cases can be incorporated
later if quad-pipe capabilities are required.

Signed-off-by: Jun Nie <jun.nie@linaro.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Jessica Zhang <quic_jesszhan@quicinc.com>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c         | 27 +++++++++++++++++------
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h         |  6 ++---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c      | 28 ++++++++----------------
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h |  2 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h   |  2 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h      |  2 +-
 6 files changed, 35 insertions(+), 32 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index e925d93b38feac0594d735fdc2c5b9fd5ae83e6a..7a88a26d04b46c7df86eebec27c7cda28725f6ea 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -200,7 +200,7 @@ static int dpu_crtc_get_lm_crc(struct drm_crtc *crtc,
 		struct dpu_crtc_state *crtc_state)
 {
 	struct dpu_crtc_mixer *m;
-	u32 crcs[CRTC_DUAL_MIXERS];
+	u32 crcs[CRTC_QUAD_MIXERS];
 
 	int rc = 0;
 	int i;
@@ -1328,6 +1328,7 @@ static struct msm_display_topology dpu_crtc_get_topology(
 	struct drm_display_mode *mode = &crtc_state->adjusted_mode;
 	struct msm_display_topology topology = {0};
 	struct drm_encoder *drm_enc;
+	u32 num_rt_intf;
 
 	drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc_state->encoder_mask)
 		dpu_encoder_update_topology(drm_enc, &topology, crtc_state->state,
@@ -1341,11 +1342,14 @@ static struct msm_display_topology dpu_crtc_get_topology(
 	 * Dual display
 	 * 2 LM, 2 INTF ( Split display using 2 interfaces)
 	 *
+	 * If DSC is enabled, try to use 4:4:2 topology if there is enough
+	 * resource. Otherwise, use 2:2:2 topology.
+	 *
 	 * Single display
 	 * 1 LM, 1 INTF
 	 * 2 LM, 1 INTF (stream merge to support high resolution interfaces)
 	 *
-	 * If DSC is enabled, use 2 LMs for 2:2:1 topology
+	 * If DSC is enabled, use 2:2:1 topology
 	 *
 	 * Add dspps to the reservation requirements if ctm is requested
 	 *
@@ -1357,14 +1361,23 @@ static struct msm_display_topology dpu_crtc_get_topology(
 	 * (mode->hdisplay > MAX_HDISPLAY_SPLIT) check.
 	 */
 
-	if (topology.num_intf == 2 && !topology.cwb_enabled)
-		topology.num_lm = 2;
-	else if (topology.num_dsc == 2)
+	num_rt_intf = topology.num_intf;
+	if (topology.cwb_enabled)
+		num_rt_intf--;
+
+	if (topology.num_dsc) {
+		if (dpu_kms->catalog->dsc_count >= num_rt_intf * 2)
+			topology.num_dsc = num_rt_intf * 2;
+		else
+			topology.num_dsc = num_rt_intf;
+		topology.num_lm = topology.num_dsc;
+	} else if (num_rt_intf == 2) {
 		topology.num_lm = 2;
-	else if (dpu_kms->catalog->caps->has_3d_merge)
+	} else if (dpu_kms->catalog->caps->has_3d_merge) {
 		topology.num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1;
-	else
+	} else {
 		topology.num_lm = 1;
+	}
 
 	if (crtc_state->ctm)
 		topology.num_dspp = topology.num_lm;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
index 6eaba5696e8e6bd1246a9895c4c8714ca6589b10..455073c7025b0bcb970d8817f197d9bcacc6dca5 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
@@ -210,7 +210,7 @@ struct dpu_crtc_state {
 
 	bool bw_control;
 	bool bw_split_vote;
-	struct drm_rect lm_bounds[CRTC_DUAL_MIXERS];
+	struct drm_rect lm_bounds[CRTC_QUAD_MIXERS];
 
 	uint64_t input_fence_timeout_ns;
 
@@ -218,10 +218,10 @@ struct dpu_crtc_state {
 
 	/* HW Resources reserved for the crtc */
 	u32 num_mixers;
-	struct dpu_crtc_mixer mixers[CRTC_DUAL_MIXERS];
+	struct dpu_crtc_mixer mixers[CRTC_QUAD_MIXERS];
 
 	u32 num_ctls;
-	struct dpu_hw_ctl *hw_ctls[CRTC_DUAL_MIXERS];
+	struct dpu_hw_ctl *hw_ctls[CRTC_QUAD_MIXERS];
 
 	enum dpu_crtc_crc_source crc_source;
 	int crc_frame_skip_count;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 55b83ba6102d38a9ec97bc4d12ad31810e4b261a..3dd202e0ce94eaecfc7e401e1c9e1fe43106dc9e 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -55,7 +55,7 @@
 #define MAX_PHYS_ENCODERS_PER_VIRTUAL \
 	(MAX_H_TILES_PER_DISPLAY * NUM_PHYS_ENCODER_TYPES)
 
-#define MAX_CHANNELS_PER_ENC 2
+#define MAX_CHANNELS_PER_ENC 4
 #define MAX_CWB_PER_ENC 2
 
 #define IDLE_SHORT_TIMEOUT	1
@@ -675,22 +675,12 @@ void dpu_encoder_update_topology(struct drm_encoder *drm_enc,
 
 	dsc = dpu_encoder_get_dsc_config(drm_enc);
 
-	/* We only support 2 DSC mode (with 2 LM and 1 INTF) */
-	if (dsc) {
-		/*
-		 * Use 2 DSC encoders, 2 layer mixers and 1 or 2 interfaces
-		 * when Display Stream Compression (DSC) is enabled,
-		 * and when enough DSC blocks are available.
-		 * This is power-optimal and can drive up to (including) 4k
-		 * screens.
-		 */
-		WARN(topology->num_intf > 2,
-		     "DSC topology cannot support more than 2 interfaces\n");
-		if (topology->num_intf >= 2 || dpu_kms->catalog->dsc_count >= 2)
-			topology->num_dsc = 2;
-		else
-			topology->num_dsc = 1;
-	}
+	/*
+	 * Set DSC number as 1 to mark the enabled status, will be adjusted
+	 * in dpu_crtc_get_topology()
+	 */
+	if (dsc)
+		topology->num_dsc = 1;
 
 	connector = drm_atomic_get_new_connector_for_encoder(state, drm_enc);
 	if (!connector)
@@ -2181,8 +2171,8 @@ static void dpu_encoder_helper_reset_mixers(struct dpu_encoder_phys *phys_enc)
 	struct dpu_hw_mixer_cfg mixer;
 	int i, num_lm;
 	struct dpu_global_state *global_state;
-	struct dpu_hw_blk *hw_lm[2];
-	struct dpu_hw_mixer *hw_mixer[2];
+	struct dpu_hw_blk *hw_lm[MAX_CHANNELS_PER_ENC];
+	struct dpu_hw_mixer *hw_mixer[MAX_CHANNELS_PER_ENC];
 	struct dpu_hw_ctl *ctl = phys_enc->hw_ctl;
 
 	memset(&mixer, 0, sizeof(mixer));
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
index 61b22d9494546885db609efa156222792af73d2a..09395d7910ac87c035b65cf476350bf6c9619612 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -302,7 +302,7 @@ static inline enum dpu_3d_blend_mode dpu_encoder_helper_get_3d_blend_mode(
 
 	/* Use merge_3d unless DSC MERGE topology is used */
 	if (phys_enc->split_role == ENC_ROLE_SOLO &&
-	    dpu_cstate->num_mixers == CRTC_DUAL_MIXERS &&
+	    (dpu_cstate->num_mixers != 1) &&
 	    !dpu_encoder_use_dsc_merge(phys_enc->parent))
 		return BLEND_3D_H_ROW_INT;
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
index f0768f54e9b3d5a3f5a7bec4b66127f2e2284cfd..21c980f8e2e3e8469055ff6bfbba1afdbb88bfbc 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
@@ -24,7 +24,7 @@
 #define DPU_MAX_IMG_WIDTH 0x3fff
 #define DPU_MAX_IMG_HEIGHT 0x3fff
 
-#define CRTC_DUAL_MIXERS	2
+#define CRTC_QUAD_MIXERS	4
 
 #define MAX_XIN_COUNT 16
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
index e4875a1f638db6f1983d9c51cb399319d27675e9..5cedcda285273a46cd6e11da63cde92cab94b9f4 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
@@ -34,7 +34,7 @@
 #define DPU_MAX_PLANES			4
 #endif
 
-#define STAGES_PER_PLANE		1
+#define STAGES_PER_PLANE		2
 #define PIPES_PER_STAGE			2
 #define PIPES_PER_PLANE			(PIPES_PER_STAGE * STAGES_PER_PLANE)
 #ifndef DPU_MAX_DE_CURVES

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface
  2025-09-18 13:28 [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface Jun Nie
                   ` (9 preceding siblings ...)
  2025-09-18 13:29 ` [PATCH v16 10/10] drm/msm/dpu: Enable quad-pipe for DSC and dual-DSI case Jun Nie
@ 2025-09-19  0:41 ` Dmitry Baryshkov
  2025-09-19 18:50   ` Dmitry Baryshkov
  2025-11-14 14:26 ` Dmitry Baryshkov
  11 siblings, 1 reply; 28+ messages in thread
From: Dmitry Baryshkov @ 2025-09-19  0:41 UTC (permalink / raw)
  To: Jun Nie
  Cc: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, Jessica Zhang,
	linux-arm-msm, dri-devel, freedreno, linux-kernel, Jessica Zhang

On Thu, Sep 18, 2025 at 09:28:52PM +0800, Jun Nie wrote:
> 2 or more SSPPs and dual-DSI interface are need for super wide panel.
> And 4 DSC are preferred for power optimal in this case due to width
> limitation of SSPP and MDP clock rate constrain. This patch set
> extends number of pipes to 4 and revise related mixer blending logic
> to support quad pipe. All these changes depends on the virtual plane
> feature to split a super wide drm plane horizontally into 2 or more sub
> clip. Thus DMA of multiple SSPPs can share the effort of fetching the
> whole drm plane.
> 
> The first pipe pair co-work with the first mixer pair to cover the left
> half of screen and 2nd pair of pipes and mixers are for the right half
> of screen. If a plane is only for the right half of screen, only one
> or two of pipes in the 2nd pipe pair are valid, and no SSPP or mixer is
> assinged for invalid pipe.
> 
> For those panel that does not require quad-pipe, only 1 or 2 pipes in
> the 1st pipe pair will be used. There is no concept of right half of
> screen.
> 
> For legacy non virtual plane mode, the first 1 or 2 pipes are used for
> the single SSPP and its multi-rect mode.
>     
>     Changes in v16:
>     - Rebase to latest branch msm-next-lumag.
>     - Fix IGT test failures.
>     - Drop patches that have been merged.
>     - Link to v15: https://lore.kernel.org/r/20250819-v6-16-rc2-quad-pipe-upstream-v15-0-2c7a85089db8@linaro.org

Thanks. It's too invasive and too late for 6.18, but I've started the
test run at https://gitlab.freedesktop.org/drm/msm/-/merge_requests/191


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v16 10/10] drm/msm/dpu: Enable quad-pipe for DSC and dual-DSI case
  2025-09-18 13:29 ` [PATCH v16 10/10] drm/msm/dpu: Enable quad-pipe for DSC and dual-DSI case Jun Nie
@ 2025-09-19 16:57   ` Dmitry Baryshkov
  2025-11-29 16:37   ` Marijn Suijten
  1 sibling, 0 replies; 28+ messages in thread
From: Dmitry Baryshkov @ 2025-09-19 16:57 UTC (permalink / raw)
  To: Jun Nie
  Cc: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, Jessica Zhang,
	linux-arm-msm, dri-devel, freedreno, linux-kernel, Jessica Zhang

On Thu, Sep 18, 2025 at 09:29:02PM +0800, Jun Nie wrote:
> To support high-resolution cases that exceed the width limitation of
> a pair of SSPPs, or scenarios that surpass the maximum MDP clock rate,
> additional pipes are necessary to enable parallel data processing
> within the SSPP width constraints and MDP clock rate.
> 
> Request 4 mixers and 4 DSCs for high-resolution cases where both DSC
> and dual interfaces are enabled. More use cases can be incorporated
> later if quad-pipe capabilities are required.
> 
> Signed-off-by: Jun Nie <jun.nie@linaro.org>
> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> Reviewed-by: Jessica Zhang <quic_jesszhan@quicinc.com>
> ---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c         | 27 +++++++++++++++++------
>  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h         |  6 ++---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c      | 28 ++++++++----------------
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h |  2 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h   |  2 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h      |  2 +-
>  6 files changed, 35 insertions(+), 32 deletions(-)
> 
Please fix the LKP report.

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface
  2025-09-19  0:41 ` [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface Dmitry Baryshkov
@ 2025-09-19 18:50   ` Dmitry Baryshkov
  0 siblings, 0 replies; 28+ messages in thread
From: Dmitry Baryshkov @ 2025-09-19 18:50 UTC (permalink / raw)
  To: Jun Nie
  Cc: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, Jessica Zhang,
	linux-arm-msm, dri-devel, freedreno, linux-kernel, Jessica Zhang

On Fri, Sep 19, 2025 at 03:41:56AM +0300, Dmitry Baryshkov wrote:
> On Thu, Sep 18, 2025 at 09:28:52PM +0800, Jun Nie wrote:
> > 2 or more SSPPs and dual-DSI interface are need for super wide panel.
> > And 4 DSC are preferred for power optimal in this case due to width
> > limitation of SSPP and MDP clock rate constrain. This patch set
> > extends number of pipes to 4 and revise related mixer blending logic
> > to support quad pipe. All these changes depends on the virtual plane
> > feature to split a super wide drm plane horizontally into 2 or more sub
> > clip. Thus DMA of multiple SSPPs can share the effort of fetching the
> > whole drm plane.
> > 
> > The first pipe pair co-work with the first mixer pair to cover the left
> > half of screen and 2nd pair of pipes and mixers are for the right half
> > of screen. If a plane is only for the right half of screen, only one
> > or two of pipes in the 2nd pipe pair are valid, and no SSPP or mixer is
> > assinged for invalid pipe.
> > 
> > For those panel that does not require quad-pipe, only 1 or 2 pipes in
> > the 1st pipe pair will be used. There is no concept of right half of
> > screen.
> > 
> > For legacy non virtual plane mode, the first 1 or 2 pipes are used for
> > the single SSPP and its multi-rect mode.
> >     
> >     Changes in v16:
> >     - Rebase to latest branch msm-next-lumag.
> >     - Fix IGT test failures.
> >     - Drop patches that have been merged.
> >     - Link to v15: https://lore.kernel.org/r/20250819-v6-16-rc2-quad-pipe-upstream-v15-0-2c7a85089db8@linaro.org
> 
> Thanks. It's too invasive and too late for 6.18, but I've started the
> test run at https://gitlab.freedesktop.org/drm/msm/-/merge_requests/191

JFYI: this has passed the IGT testing, so it will be picked up soon
after 6.18-rc1.

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface
  2025-09-18 13:28 [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface Jun Nie
                   ` (10 preceding siblings ...)
  2025-09-19  0:41 ` [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface Dmitry Baryshkov
@ 2025-11-14 14:26 ` Dmitry Baryshkov
  11 siblings, 0 replies; 28+ messages in thread
From: Dmitry Baryshkov @ 2025-11-14 14:26 UTC (permalink / raw)
  To: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, Jessica Zhang, Jun Nie
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jessica Zhang

On Thu, 18 Sep 2025 21:28:52 +0800, Jun Nie wrote:
> 2 or more SSPPs and dual-DSI interface are need for super wide panel.
> And 4 DSC are preferred for power optimal in this case due to width
> limitation of SSPP and MDP clock rate constrain. This patch set
> extends number of pipes to 4 and revise related mixer blending logic
> to support quad pipe. All these changes depends on the virtual plane
> feature to split a super wide drm plane horizontally into 2 or more sub
> clip. Thus DMA of multiple SSPPs can share the effort of fetching the
> whole drm plane.
> 
> [...]

Applied to msm-next, thanks!

[01/10] drm/msm/dpu: fix mixer number counter on allocation
        https://gitlab.freedesktop.org/lumag/msm/-/commit/74c4efe691e7
[02/10] drm/msm/dpu: bind correct pingpong for quad pipe
        https://gitlab.freedesktop.org/lumag/msm/-/commit/e4f87fdd911e
[03/10] drm/msm/dpu: Add pipe as trace argument
        https://gitlab.freedesktop.org/lumag/msm/-/commit/2c94547e0ced
[04/10] drm/msm/dpu: handle pipes as array
        https://gitlab.freedesktop.org/lumag/msm/-/commit/fb4c972b638f
[05/10] drm/msm/dpu: split PIPES_PER_STAGE definition per plane and mixer
        https://gitlab.freedesktop.org/lumag/msm/-/commit/5d45171e262e
[06/10] drm/msm/dpu: Use dedicated WB number definition
        https://gitlab.freedesktop.org/lumag/msm/-/commit/aed75641425c
[07/10] drm/msm/dpu: blend pipes per mixer pairs config
        https://gitlab.freedesktop.org/lumag/msm/-/commit/c11684cce9e5
[08/10] drm/msm/dpu: support SSPP assignment for quad-pipe case
        https://gitlab.freedesktop.org/lumag/msm/-/commit/cf63d61337c3
[09/10] drm/msm/dpu: support plane splitting in quad-pipe case
        https://gitlab.freedesktop.org/lumag/msm/-/commit/5978864e34b6
[10/10] drm/msm/dpu: Enable quad-pipe for DSC and dual-DSI case
        https://gitlab.freedesktop.org/lumag/msm/-/commit/cd432dfed2ab

Best regards,
-- 
With best wishes
Dmitry



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v16 10/10] drm/msm/dpu: Enable quad-pipe for DSC and dual-DSI case
  2025-09-18 13:29 ` [PATCH v16 10/10] drm/msm/dpu: Enable quad-pipe for DSC and dual-DSI case Jun Nie
  2025-09-19 16:57   ` Dmitry Baryshkov
@ 2025-11-29 16:37   ` Marijn Suijten
  2025-12-02  4:18     ` Jun Nie
  2025-12-10 19:30     ` Dmitry Baryshkov
  1 sibling, 2 replies; 28+ messages in thread
From: Marijn Suijten @ 2025-11-29 16:37 UTC (permalink / raw)
  To: Jun Nie
  Cc: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, David Airlie,
	Simona Vetter, Rob Clark, Jessica Zhang, linux-arm-msm, dri-devel,
	freedreno, linux-kernel, Jessica Zhang

On 2025-09-18 21:29:02, Jun Nie wrote:
> To support high-resolution cases that exceed the width limitation of
> a pair of SSPPs, or scenarios that surpass the maximum MDP clock rate,
> additional pipes are necessary to enable parallel data processing
> within the SSPP width constraints and MDP clock rate.
> 
> Request 4 mixers and 4 DSCs for high-resolution cases where both DSC
> and dual interfaces are enabled. More use cases can be incorporated
> later if quad-pipe capabilities are required.
> 
> Signed-off-by: Jun Nie <jun.nie@linaro.org>
> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> Reviewed-by: Jessica Zhang <quic_jesszhan@quicinc.com>
> ---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c         | 27 +++++++++++++++++------
>  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h         |  6 ++---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c      | 28 ++++++++----------------
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h |  2 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h   |  2 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h      |  2 +-
>  6 files changed, 35 insertions(+), 32 deletions(-)

With this patch applied, I get the following crash on the Sony Xperia 1 III, a
dual-DSI dual-DSC device:

	Unable to handle kernel NULL pointer dereference at virtual address 0000000000000020
	Mem abort info:
	  ESR = 0x0000000096000004
	  EC = 0x25: DABT (current EL), IL = 32 bits
	  SET = 0, FnV = 0
	  EA = 0, S1PTW = 0
	  FSC = 0x04: level 0 translation fault
	Data abort info:
	  ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000
	  CM = 0, WnR = 0, TnD = 0, TagAccess = 0
	  GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
	user pgtable: 4k pages, 48-bit VAs, pgdp=000000012d4e1000
	[0000000000000020] pgd=0000000000000000, p4d=0000000000000000
	Internal error: Oops: 0000000096000004 [#1]  SMP
	Modules linked in: msm drm_client_lib ubwc_config drm_dp_aux_bus gpu_sched drm_gpuvm drm_exec
	CPU: 5 UID: 0 PID: 3081 Comm: (sd-close) Tainted: G     U              6.18.0-rc7-next-20251127-SoMainline-12422-g10b6db5b056d-dirty #21 NONE
	Tainted: [U]=USER
	Hardware name: Sony Xperia 1 III (DT)
	pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
	pc : dpu_plane_atomic_check_sspp.isra.0+0x88/0x3f4 [msm]
	lr : dpu_plane_atomic_check_sspp.isra.0+0x84/0x3f4 [msm]
	sp : ffff800081e23940
	x29: ffff800081e23950 x28: ffff0000bf2700d0 x27: 0000000000000a00
	x26: ffff0000bf270000 x25: 0000000000000a00 x24: ffff0000bd0e5c18
	x23: ffff000087a6c080 x22: 0000000000000224 x21: ffff00008ce88080
	x20: 0000000000000002 x19: ffff0000bf270138 x18: ffff8000818350b0
	x17: 000000040044ffff x16: ffffc488ae2e37e0 x15: 0000000000000005
	x14: 0000000000000a00 x13: 0000000000000000 x12: 0000000000000138
	x11: 0000000000000000 x10: 0000000000000012 x9 : 0000000000000000
	x8 : 0000000000000a00 x7 : 0000000000000000 x6 : 0000000000000000
	x5 : 0000000000000002 x4 : 0000000000000000 x3 : ffffc48897741db0
	x2 : 0000000000000000 x1 : 0000000000000000 x0 : 0000000000000000
	Call trace:
	 dpu_plane_atomic_check_sspp.isra.0+0x88/0x3f4 [msm] (P)
	 dpu_plane_atomic_check+0x100/0x1a0 [msm]
	 drm_atomic_helper_check_planes+0xd8/0x224
	 drm_atomic_helper_check+0x50/0xb4
	 msm_atomic_check+0xd0/0xe0 [msm]
	 drm_atomic_check_only+0x4e0/0x928
	 drm_atomic_commit+0x50/0xd4
	 drm_client_modeset_commit_atomic+0x200/0x260
	 drm_client_modeset_commit_locked+0x64/0x180
	 drm_client_modeset_commit+0x30/0x60
	 drm_fb_helper_lastclose+0x60/0xb0
	 drm_fbdev_client_restore+0x18/0x38 [drm_client_lib]
	 drm_client_dev_restore+0xac/0xf8
	 drm_release+0x124/0x158
	 __fput+0xd4/0x2e4
	 fput_close_sync+0x3c/0xe0
	 __arm64_sys_close+0x3c/0x84
	 invoke_syscall.constprop.0+0x44/0x100
	 el0_svc_common.constprop.0+0x3c/0xe4
	 do_el0_svc+0x20/0x3c
	 el0_svc+0x38/0x110
	 el0t_64_sync_handler+0xa8/0xec
	 el0t_64_sync+0x1a0/0x1a4
	Code: 2a1403e5 52800082 94008e28 f9400380 (f940101b)
	---[ end trace 0000000000000000 ]---
	pstore: backend (ramoops) writing error (-28)
	[drm:dpu_encoder_frame_done_timeout:2726] [dpu error]enc33 frame done timeout

I don't see any thought given to it in the extremely terse patch description,
but this patch seems to unconditionally select 4 DSCs and 4 LMs on this device
because the underlying SM8350 SoC has 4 available in its catalog - while it
was previously affixed to 2:2:2 matching the downstream and known-working
configuration of this device - and I can only imagine things are rolling
downhill from there.

faddr2line seems to be failing for me, but this is the line
`dpu_plane_atomic_check_sspp.isra.0+0x88` seems to be referring to:

	aarch64-linux-gnu-objdump .output/drivers/gpu/drm/msm/msm.ko -dS | grep dpu_plane_atomic_check_sspp.isra.0\> -A80
	00000000000671ac <dpu_plane_atomic_check_sspp.isra.0>:
	static int dpu_plane_atomic_check_sspp(struct drm_plane *plane,
	...
	   67234:	f940101b 	ldr	x27, [x0, #32]
		if (!(sblk->scaler_blk.len && pipe->sspp->ops.setup_scaler) &&

Please help resolve this issue, as I am not understanding the thought process
behind this patch and unsure how to solve this issue short of just reverting it.

Looking forward to some assistance, thanks;
- Marijn

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v16 10/10] drm/msm/dpu: Enable quad-pipe for DSC and dual-DSI case
  2025-11-29 16:37   ` Marijn Suijten
@ 2025-12-02  4:18     ` Jun Nie
  2025-12-10 19:30     ` Dmitry Baryshkov
  1 sibling, 0 replies; 28+ messages in thread
From: Jun Nie @ 2025-12-02  4:18 UTC (permalink / raw)
  To: Marijn Suijten
  Cc: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, David Airlie,
	Simona Vetter, Rob Clark, Jessica Zhang, linux-arm-msm, dri-devel,
	freedreno, linux-kernel, Jessica Zhang

Marijn Suijten <marijn.suijten@somainline.org> 于2025年11月30日周日 00:37写道:
>
> On 2025-09-18 21:29:02, Jun Nie wrote:
> > To support high-resolution cases that exceed the width limitation of
> > a pair of SSPPs, or scenarios that surpass the maximum MDP clock rate,
> > additional pipes are necessary to enable parallel data processing
> > within the SSPP width constraints and MDP clock rate.
> >
> > Request 4 mixers and 4 DSCs for high-resolution cases where both DSC
> > and dual interfaces are enabled. More use cases can be incorporated
> > later if quad-pipe capabilities are required.
> >
> > Signed-off-by: Jun Nie <jun.nie@linaro.org>
> > Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > Reviewed-by: Jessica Zhang <quic_jesszhan@quicinc.com>
> > ---
> >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c         | 27 +++++++++++++++++------
> >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h         |  6 ++---
> >  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c      | 28 ++++++++----------------
> >  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h |  2 +-
> >  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h   |  2 +-
> >  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h      |  2 +-
> >  6 files changed, 35 insertions(+), 32 deletions(-)
>
> With this patch applied, I get the following crash on the Sony Xperia 1 III, a
> dual-DSI dual-DSC device:
>
>         Unable to handle kernel NULL pointer dereference at virtual address 0000000000000020
>         Mem abort info:
>           ESR = 0x0000000096000004
>           EC = 0x25: DABT (current EL), IL = 32 bits
>           SET = 0, FnV = 0
>           EA = 0, S1PTW = 0
>           FSC = 0x04: level 0 translation fault
>         Data abort info:
>           ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000
>           CM = 0, WnR = 0, TnD = 0, TagAccess = 0
>           GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
>         user pgtable: 4k pages, 48-bit VAs, pgdp=000000012d4e1000
>         [0000000000000020] pgd=0000000000000000, p4d=0000000000000000
>         Internal error: Oops: 0000000096000004 [#1]  SMP
>         Modules linked in: msm drm_client_lib ubwc_config drm_dp_aux_bus gpu_sched drm_gpuvm drm_exec
>         CPU: 5 UID: 0 PID: 3081 Comm: (sd-close) Tainted: G     U              6.18.0-rc7-next-20251127-SoMainline-12422-g10b6db5b056d-dirty #21 NONE
>         Tainted: [U]=USER
>         Hardware name: Sony Xperia 1 III (DT)
>         pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
>         pc : dpu_plane_atomic_check_sspp.isra.0+0x88/0x3f4 [msm]
>         lr : dpu_plane_atomic_check_sspp.isra.0+0x84/0x3f4 [msm]
>         sp : ffff800081e23940
>         x29: ffff800081e23950 x28: ffff0000bf2700d0 x27: 0000000000000a00
>         x26: ffff0000bf270000 x25: 0000000000000a00 x24: ffff0000bd0e5c18
>         x23: ffff000087a6c080 x22: 0000000000000224 x21: ffff00008ce88080
>         x20: 0000000000000002 x19: ffff0000bf270138 x18: ffff8000818350b0
>         x17: 000000040044ffff x16: ffffc488ae2e37e0 x15: 0000000000000005
>         x14: 0000000000000a00 x13: 0000000000000000 x12: 0000000000000138
>         x11: 0000000000000000 x10: 0000000000000012 x9 : 0000000000000000
>         x8 : 0000000000000a00 x7 : 0000000000000000 x6 : 0000000000000000
>         x5 : 0000000000000002 x4 : 0000000000000000 x3 : ffffc48897741db0
>         x2 : 0000000000000000 x1 : 0000000000000000 x0 : 0000000000000000
>         Call trace:
>          dpu_plane_atomic_check_sspp.isra.0+0x88/0x3f4 [msm] (P)
>          dpu_plane_atomic_check+0x100/0x1a0 [msm]
>          drm_atomic_helper_check_planes+0xd8/0x224
>          drm_atomic_helper_check+0x50/0xb4
>          msm_atomic_check+0xd0/0xe0 [msm]
>          drm_atomic_check_only+0x4e0/0x928
>          drm_atomic_commit+0x50/0xd4
>          drm_client_modeset_commit_atomic+0x200/0x260
>          drm_client_modeset_commit_locked+0x64/0x180
>          drm_client_modeset_commit+0x30/0x60
>          drm_fb_helper_lastclose+0x60/0xb0
>          drm_fbdev_client_restore+0x18/0x38 [drm_client_lib]
>          drm_client_dev_restore+0xac/0xf8
>          drm_release+0x124/0x158
>          __fput+0xd4/0x2e4
>          fput_close_sync+0x3c/0xe0
>          __arm64_sys_close+0x3c/0x84
>          invoke_syscall.constprop.0+0x44/0x100
>          el0_svc_common.constprop.0+0x3c/0xe4
>          do_el0_svc+0x20/0x3c
>          el0_svc+0x38/0x110
>          el0t_64_sync_handler+0xa8/0xec
>          el0t_64_sync+0x1a0/0x1a4
>         Code: 2a1403e5 52800082 94008e28 f9400380 (f940101b)
>         ---[ end trace 0000000000000000 ]---
>         pstore: backend (ramoops) writing error (-28)
>         [drm:dpu_encoder_frame_done_timeout:2726] [dpu error]enc33 frame done timeout
>
> I don't see any thought given to it in the extremely terse patch description,
> but this patch seems to unconditionally select 4 DSCs and 4 LMs on this device
> because the underlying SM8350 SoC has 4 available in its catalog - while it
> was previously affixed to 2:2:2 matching the downstream and known-working
> configuration of this device - and I can only imagine things are rolling
> downhill from there.

This patch expands pipe array size from 2 to 4, and changes the
topology decision making.
There is an assumption that 2 stages(4LMs) should be allocated in case
of 2 interfaces with
DSC enabled, because it is a very high resolution use case. This fails
for your 2:2:2 use case.
But I still expect there are only 2 pipes info filled for your case,
and the later 2 pipes shall be
 bypassed in dpu_plane_atomic_check_sspp() and does not introduce
panic. So there is
bug in SSPP handling.

What's your IRC ID and timezone? IRC shall be much more efficient, if
you want to discuss
more detail and debug support.
>
> faddr2line seems to be failing for me, but this is the line
> `dpu_plane_atomic_check_sspp.isra.0+0x88` seems to be referring to:
>
>         aarch64-linux-gnu-objdump .output/drivers/gpu/drm/msm/msm.ko -dS | grep dpu_plane_atomic_check_sspp.isra.0\> -A80
>         00000000000671ac <dpu_plane_atomic_check_sspp.isra.0>:
>         static int dpu_plane_atomic_check_sspp(struct drm_plane *plane,
>         ...
>            67234:       f940101b        ldr     x27, [x0, #32]
>                 if (!(sblk->scaler_blk.len && pipe->sspp->ops.setup_scaler) &&
>
> Please help resolve this issue, as I am not understanding the thought process
> behind this patch and unsure how to solve this issue short of just reverting it.
>
> Looking forward to some assistance, thanks;
> - Marijn

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v16 10/10] drm/msm/dpu: Enable quad-pipe for DSC and dual-DSI case
  2025-11-29 16:37   ` Marijn Suijten
  2025-12-02  4:18     ` Jun Nie
@ 2025-12-10 19:30     ` Dmitry Baryshkov
  2025-12-11 15:53       ` Jun Nie
  1 sibling, 1 reply; 28+ messages in thread
From: Dmitry Baryshkov @ 2025-12-10 19:30 UTC (permalink / raw)
  To: Marijn Suijten
  Cc: Jun Nie, Abhinav Kumar, Dmitry Baryshkov, Sean Paul, David Airlie,
	Simona Vetter, Rob Clark, Jessica Zhang, linux-arm-msm, dri-devel,
	freedreno, linux-kernel, Jessica Zhang

On Sat, Nov 29, 2025 at 05:37:43PM +0100, Marijn Suijten wrote:
> On 2025-09-18 21:29:02, Jun Nie wrote:
> > To support high-resolution cases that exceed the width limitation of
> > a pair of SSPPs, or scenarios that surpass the maximum MDP clock rate,
> > additional pipes are necessary to enable parallel data processing
> > within the SSPP width constraints and MDP clock rate.
> > 
> > Request 4 mixers and 4 DSCs for high-resolution cases where both DSC
> > and dual interfaces are enabled. More use cases can be incorporated
> > later if quad-pipe capabilities are required.
> > 
> > Signed-off-by: Jun Nie <jun.nie@linaro.org>
> > Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > Reviewed-by: Jessica Zhang <quic_jesszhan@quicinc.com>
> > ---
> >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c         | 27 +++++++++++++++++------
> >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h         |  6 ++---
> >  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c      | 28 ++++++++----------------
> >  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h |  2 +-
> >  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h   |  2 +-
> >  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h      |  2 +-
> >  6 files changed, 35 insertions(+), 32 deletions(-)
> 
> With this patch applied, I get the following crash on the Sony Xperia 1 III, a
> dual-DSI dual-DSC device:
> 
> 	Unable to handle kernel NULL pointer dereference at virtual address 0000000000000020
> 	Mem abort info:
> 	  ESR = 0x0000000096000004
> 	  EC = 0x25: DABT (current EL), IL = 32 bits
> 	  SET = 0, FnV = 0
> 	  EA = 0, S1PTW = 0
> 	  FSC = 0x04: level 0 translation fault
> 	Data abort info:
> 	  ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000
> 	  CM = 0, WnR = 0, TnD = 0, TagAccess = 0
> 	  GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
> 	user pgtable: 4k pages, 48-bit VAs, pgdp=000000012d4e1000
> 	[0000000000000020] pgd=0000000000000000, p4d=0000000000000000
> 	Internal error: Oops: 0000000096000004 [#1]  SMP
> 	Modules linked in: msm drm_client_lib ubwc_config drm_dp_aux_bus gpu_sched drm_gpuvm drm_exec
> 	CPU: 5 UID: 0 PID: 3081 Comm: (sd-close) Tainted: G     U              6.18.0-rc7-next-20251127-SoMainline-12422-g10b6db5b056d-dirty #21 NONE
> 	Tainted: [U]=USER
> 	Hardware name: Sony Xperia 1 III (DT)
> 	pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
> 	pc : dpu_plane_atomic_check_sspp.isra.0+0x88/0x3f4 [msm]
> 	lr : dpu_plane_atomic_check_sspp.isra.0+0x84/0x3f4 [msm]
> 	sp : ffff800081e23940
> 	x29: ffff800081e23950 x28: ffff0000bf2700d0 x27: 0000000000000a00
> 	x26: ffff0000bf270000 x25: 0000000000000a00 x24: ffff0000bd0e5c18
> 	x23: ffff000087a6c080 x22: 0000000000000224 x21: ffff00008ce88080
> 	x20: 0000000000000002 x19: ffff0000bf270138 x18: ffff8000818350b0
> 	x17: 000000040044ffff x16: ffffc488ae2e37e0 x15: 0000000000000005
> 	x14: 0000000000000a00 x13: 0000000000000000 x12: 0000000000000138
> 	x11: 0000000000000000 x10: 0000000000000012 x9 : 0000000000000000
> 	x8 : 0000000000000a00 x7 : 0000000000000000 x6 : 0000000000000000
> 	x5 : 0000000000000002 x4 : 0000000000000000 x3 : ffffc48897741db0
> 	x2 : 0000000000000000 x1 : 0000000000000000 x0 : 0000000000000000
> 	Call trace:
> 	 dpu_plane_atomic_check_sspp.isra.0+0x88/0x3f4 [msm] (P)
> 	 dpu_plane_atomic_check+0x100/0x1a0 [msm]
> 	 drm_atomic_helper_check_planes+0xd8/0x224
> 	 drm_atomic_helper_check+0x50/0xb4
> 	 msm_atomic_check+0xd0/0xe0 [msm]
> 	 drm_atomic_check_only+0x4e0/0x928
> 	 drm_atomic_commit+0x50/0xd4
> 	 drm_client_modeset_commit_atomic+0x200/0x260
> 	 drm_client_modeset_commit_locked+0x64/0x180
> 	 drm_client_modeset_commit+0x30/0x60
> 	 drm_fb_helper_lastclose+0x60/0xb0
> 	 drm_fbdev_client_restore+0x18/0x38 [drm_client_lib]
> 	 drm_client_dev_restore+0xac/0xf8
> 	 drm_release+0x124/0x158
> 	 __fput+0xd4/0x2e4
> 	 fput_close_sync+0x3c/0xe0
> 	 __arm64_sys_close+0x3c/0x84
> 	 invoke_syscall.constprop.0+0x44/0x100
> 	 el0_svc_common.constprop.0+0x3c/0xe4
> 	 do_el0_svc+0x20/0x3c
> 	 el0_svc+0x38/0x110
> 	 el0t_64_sync_handler+0xa8/0xec
> 	 el0t_64_sync+0x1a0/0x1a4
> 	Code: 2a1403e5 52800082 94008e28 f9400380 (f940101b)
> 	---[ end trace 0000000000000000 ]---
> 	pstore: backend (ramoops) writing error (-28)
> 	[drm:dpu_encoder_frame_done_timeout:2726] [dpu error]enc33 frame done timeout
> 
> I don't see any thought given to it in the extremely terse patch description,
> but this patch seems to unconditionally select 4 DSCs and 4 LMs on this device
> because the underlying SM8350 SoC has 4 available in its catalog - while it
> was previously affixed to 2:2:2 matching the downstream and known-working
> configuration of this device - and I can only imagine things are rolling
> downhill from there.
> 
> faddr2line seems to be failing for me, but this is the line
> `dpu_plane_atomic_check_sspp.isra.0+0x88` seems to be referring to:
> 
> 	aarch64-linux-gnu-objdump .output/drivers/gpu/drm/msm/msm.ko -dS | grep dpu_plane_atomic_check_sspp.isra.0\> -A80
> 	00000000000671ac <dpu_plane_atomic_check_sspp.isra.0>:
> 	static int dpu_plane_atomic_check_sspp(struct drm_plane *plane,
> 	...
> 	   67234:	f940101b 	ldr	x27, [x0, #32]
> 		if (!(sblk->scaler_blk.len && pipe->sspp->ops.setup_scaler) &&

I think it is:

        pipe_hw_caps = pipe->sspp->cap;
    14bc:       f9401018        ldr     x24, [x0, #32]


So, please check why pipe->sspp becomes NULL (or where do we miss the
NULL check for pipe->sspp).


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v16 10/10] drm/msm/dpu: Enable quad-pipe for DSC and dual-DSI case
  2025-12-10 19:30     ` Dmitry Baryshkov
@ 2025-12-11 15:53       ` Jun Nie
  2025-12-18 22:04         ` Marijn Suijten
  0 siblings, 1 reply; 28+ messages in thread
From: Jun Nie @ 2025-12-11 15:53 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Marijn Suijten, Abhinav Kumar, Dmitry Baryshkov, Sean Paul,
	David Airlie, Simona Vetter, Rob Clark, linux-arm-msm, dri-devel,
	freedreno, linux-kernel

Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> 于2025年12月11日周四 03:30写道:
>
> On Sat, Nov 29, 2025 at 05:37:43PM +0100, Marijn Suijten wrote:
> > On 2025-09-18 21:29:02, Jun Nie wrote:
> > > To support high-resolution cases that exceed the width limitation of
> > > a pair of SSPPs, or scenarios that surpass the maximum MDP clock rate,
> > > additional pipes are necessary to enable parallel data processing
> > > within the SSPP width constraints and MDP clock rate.
> > >
> > > Request 4 mixers and 4 DSCs for high-resolution cases where both DSC
> > > and dual interfaces are enabled. More use cases can be incorporated
> > > later if quad-pipe capabilities are required.
> > >
> > > Signed-off-by: Jun Nie <jun.nie@linaro.org>
> > > Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > Reviewed-by: Jessica Zhang <quic_jesszhan@quicinc.com>
> > > ---
> > >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c         | 27 +++++++++++++++++------
> > >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h         |  6 ++---
> > >  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c      | 28 ++++++++----------------
> > >  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h |  2 +-
> > >  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h   |  2 +-
> > >  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h      |  2 +-
> > >  6 files changed, 35 insertions(+), 32 deletions(-)
> >
> > With this patch applied, I get the following crash on the Sony Xperia 1 III, a
> > dual-DSI dual-DSC device:
> >
> >       Unable to handle kernel NULL pointer dereference at virtual address 0000000000000020
> >       Mem abort info:
> >         ESR = 0x0000000096000004
> >         EC = 0x25: DABT (current EL), IL = 32 bits
> >         SET = 0, FnV = 0
> >         EA = 0, S1PTW = 0
> >         FSC = 0x04: level 0 translation fault
> >       Data abort info:
> >         ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000
> >         CM = 0, WnR = 0, TnD = 0, TagAccess = 0
> >         GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
> >       user pgtable: 4k pages, 48-bit VAs, pgdp=000000012d4e1000
> >       [0000000000000020] pgd=0000000000000000, p4d=0000000000000000
> >       Internal error: Oops: 0000000096000004 [#1]  SMP
> >       Modules linked in: msm drm_client_lib ubwc_config drm_dp_aux_bus gpu_sched drm_gpuvm drm_exec
> >       CPU: 5 UID: 0 PID: 3081 Comm: (sd-close) Tainted: G     U              6.18.0-rc7-next-20251127-SoMainline-12422-g10b6db5b056d-dirty #21 NONE
> >       Tainted: [U]=USER
> >       Hardware name: Sony Xperia 1 III (DT)
> >       pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
> >       pc : dpu_plane_atomic_check_sspp.isra.0+0x88/0x3f4 [msm]
> >       lr : dpu_plane_atomic_check_sspp.isra.0+0x84/0x3f4 [msm]
> >       sp : ffff800081e23940
> >       x29: ffff800081e23950 x28: ffff0000bf2700d0 x27: 0000000000000a00
> >       x26: ffff0000bf270000 x25: 0000000000000a00 x24: ffff0000bd0e5c18
> >       x23: ffff000087a6c080 x22: 0000000000000224 x21: ffff00008ce88080
> >       x20: 0000000000000002 x19: ffff0000bf270138 x18: ffff8000818350b0
> >       x17: 000000040044ffff x16: ffffc488ae2e37e0 x15: 0000000000000005
> >       x14: 0000000000000a00 x13: 0000000000000000 x12: 0000000000000138
> >       x11: 0000000000000000 x10: 0000000000000012 x9 : 0000000000000000
> >       x8 : 0000000000000a00 x7 : 0000000000000000 x6 : 0000000000000000
> >       x5 : 0000000000000002 x4 : 0000000000000000 x3 : ffffc48897741db0
> >       x2 : 0000000000000000 x1 : 0000000000000000 x0 : 0000000000000000
> >       Call trace:
> >        dpu_plane_atomic_check_sspp.isra.0+0x88/0x3f4 [msm] (P)
> >        dpu_plane_atomic_check+0x100/0x1a0 [msm]
> >        drm_atomic_helper_check_planes+0xd8/0x224
> >        drm_atomic_helper_check+0x50/0xb4
> >        msm_atomic_check+0xd0/0xe0 [msm]
> >        drm_atomic_check_only+0x4e0/0x928
> >        drm_atomic_commit+0x50/0xd4
> >        drm_client_modeset_commit_atomic+0x200/0x260
> >        drm_client_modeset_commit_locked+0x64/0x180
> >        drm_client_modeset_commit+0x30/0x60
> >        drm_fb_helper_lastclose+0x60/0xb0
> >        drm_fbdev_client_restore+0x18/0x38 [drm_client_lib]
> >        drm_client_dev_restore+0xac/0xf8
> >        drm_release+0x124/0x158
> >        __fput+0xd4/0x2e4
> >        fput_close_sync+0x3c/0xe0
> >        __arm64_sys_close+0x3c/0x84
> >        invoke_syscall.constprop.0+0x44/0x100
> >        el0_svc_common.constprop.0+0x3c/0xe4
> >        do_el0_svc+0x20/0x3c
> >        el0_svc+0x38/0x110
> >        el0t_64_sync_handler+0xa8/0xec
> >        el0t_64_sync+0x1a0/0x1a4
> >       Code: 2a1403e5 52800082 94008e28 f9400380 (f940101b)
> >       ---[ end trace 0000000000000000 ]---
> >       pstore: backend (ramoops) writing error (-28)
> >       [drm:dpu_encoder_frame_done_timeout:2726] [dpu error]enc33 frame done timeout
> >
> > I don't see any thought given to it in the extremely terse patch description,
> > but this patch seems to unconditionally select 4 DSCs and 4 LMs on this device
> > because the underlying SM8350 SoC has 4 available in its catalog - while it
> > was previously affixed to 2:2:2 matching the downstream and known-working
> > configuration of this device - and I can only imagine things are rolling
> > downhill from there.
> >
> > faddr2line seems to be failing for me, but this is the line
> > `dpu_plane_atomic_check_sspp.isra.0+0x88` seems to be referring to:
> >
> >       aarch64-linux-gnu-objdump .output/drivers/gpu/drm/msm/msm.ko -dS | grep dpu_plane_atomic_check_sspp.isra.0\> -A80
> >       00000000000671ac <dpu_plane_atomic_check_sspp.isra.0>:
> >       static int dpu_plane_atomic_check_sspp(struct drm_plane *plane,
> >       ...
> >          67234:       f940101b        ldr     x27, [x0, #32]
> >               if (!(sblk->scaler_blk.len && pipe->sspp->ops.setup_scaler) &&
>
> I think it is:
>
>         pipe_hw_caps = pipe->sspp->cap;
>     14bc:       f9401018        ldr     x24, [x0, #32]
>
>
> So, please check why pipe->sspp becomes NULL (or where do we miss the
> NULL check for pipe->sspp).

Yeah, per panic log and objdump, it should be due to this line. But no
clue is found
with code analysis.
Did you reproduce it? If so, what's the platform and git commit id? I
tested with
HDK8650 dual-DSI HDMI bridged monitor, but kernel does not panic.

resource mapping:
        pingpong=104 104 # # # # - - # # # # -
        mixer=104 104 # # # # - -
        ctl=104 # # # # # - -
        dspp=# # # # - - - -
        dsc=# # # # # # - -
        cdm=#
        sspp=# # # # - - - - 104 # # # # # - -
        cwb=# # # #


Hi Marijn,
Could you help collect debug info with this change? Thanks!
BTW: my irc id: niej

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index d07a6ab6e7ee1..fc61c2fbb0699 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -886,6 +886,7 @@ static int dpu_plane_atomic_check_nosspp(struct
drm_plane *plane,
                        new_plane_state->fb->width, new_plane_state->fb->height,
                        new_plane_state->rotation);

+       memset(&pstate->pipe_cfg[0], 0, PIPES_PER_PLANE *
sizeof(struct dpu_sw_pipe_cfg));
        /*
         * We have 1 mixer pair cfg for 1:1:1 and 2:2:1 topology, 2 mixer pair
         * configs for left and right half screen in case of 4:4:2 topology.
@@ -1055,6 +1056,13 @@ static int dpu_plane_atomic_check_sspp(struct
drm_plane *plane,
                if (!drm_rect_width(&pipe_cfg->src_rect))
                        continue;
                DPU_DEBUG_PLANE(pdpu, "pipe %d is in use, validate it\n", i);
+               if(!pipe->sspp) {
+                       WARN(1, "%svirtual plane pipe %d is null with
width %d height %d!!\n",
+                               dpu_use_virtual_planes ? " " : "non-",
+                               i,
+                               drm_rect_width(&pipe_cfg->src_rect),
+                               drm_rect_height(&pipe_cfg->src_rect));
+               }
                ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg,
                                                  &crtc_state->adjusted_mode,
                                                  new_plane_state);
>
>
> --
> With best wishes
> Dmitry

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH v16 09/10] drm/msm/dpu: support plane splitting in quad-pipe case
  2025-09-18 13:29 ` [PATCH v16 09/10] drm/msm/dpu: support plane splitting in " Jun Nie
@ 2025-12-18 12:44   ` Abel Vesa
  2026-01-14 14:48   ` Jun Nie
  1 sibling, 0 replies; 28+ messages in thread
From: Abel Vesa @ 2025-12-18 12:44 UTC (permalink / raw)
  To: Jun Nie
  Cc: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, Jessica Zhang,
	linux-arm-msm, dri-devel, freedreno, linux-kernel

On 25-09-18 21:29:01, Jun Nie wrote:
> The content of every half of screen is sent out via one interface in
> dual-DSI case. The content for every interface is blended by a LM
> pair in quad-pipe case, thus a LM pair should not blend any content
> that cross the half of screen in this case. Clip plane into pipes per
> left and right half screen ROI if topology is quad pipe case.
> 
> The clipped rectangle on every half of screen is futher handled by two
> pipes if its width exceeds a limit for a single pipe.
> 
> Signed-off-by: Jun Nie <jun.nie@linaro.org>
> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> Reviewed-by: Jessica Zhang <jessica.zhang@oss.qualcomm.com>

At least on Hamoa based devices (CRD and xps13) I have been seeing on every
boot the following:

arm-smmu 15000000.iommu: Unhandled context fault: fsr=0x402, iova=0x00000000, fsynr=0x3d0023, cbfrsynra=0x1c00, cb=13
arm-smmu 15000000.iommu: FSR    = 00000402 [Format=2 TF], SID=0x1c00
arm-smmu 15000000.iommu: FSYNR0 = 003d0023 [S1CBNDX=61 PNU PLVL=3]

Also there are some artifacts on eDP (no DP connected) on the xps13 with 2880x1800
(LGD 134WT1) panel. Not on CRD though.

Reverting this commit fixes it:
5978864e34b6 ("drm/msm/dpu: support plane splitting in quad-pipe case")

Discussing this off-list with Dmitry and Konrad, the conclusion was that
both this plus following commit should be reverted for the time being:

d7ec9366b15c ("drm/msm/dpu: Enable quad-pipe for DSC and dual-DSI case")

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v16 10/10] drm/msm/dpu: Enable quad-pipe for DSC and dual-DSI case
  2025-12-11 15:53       ` Jun Nie
@ 2025-12-18 22:04         ` Marijn Suijten
  0 siblings, 0 replies; 28+ messages in thread
From: Marijn Suijten @ 2025-12-18 22:04 UTC (permalink / raw)
  To: Jun Nie
  Cc: Dmitry Baryshkov, Abhinav Kumar, Dmitry Baryshkov, Sean Paul,
	David Airlie, Simona Vetter, Rob Clark, linux-arm-msm, dri-devel,
	freedreno, linux-kernel

On 2025-12-11 23:53:00, Jun Nie wrote:
> Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> ???2025???12???11????????? 03:30?????????
> >
> > On Sat, Nov 29, 2025 at 05:37:43PM +0100, Marijn Suijten wrote:
> > > On 2025-09-18 21:29:02, Jun Nie wrote:
> > > > To support high-resolution cases that exceed the width limitation of
> > > > a pair of SSPPs, or scenarios that surpass the maximum MDP clock rate,
> > > > additional pipes are necessary to enable parallel data processing
> > > > within the SSPP width constraints and MDP clock rate.
> > > >
> > > > Request 4 mixers and 4 DSCs for high-resolution cases where both DSC
> > > > and dual interfaces are enabled. More use cases can be incorporated
> > > > later if quad-pipe capabilities are required.
> > > >
> > > > Signed-off-by: Jun Nie <jun.nie@linaro.org>
> > > > Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > Reviewed-by: Jessica Zhang <quic_jesszhan@quicinc.com>
> > > > ---
> > > >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c         | 27 +++++++++++++++++------
> > > >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h         |  6 ++---
> > > >  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c      | 28 ++++++++----------------
> > > >  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h |  2 +-
> > > >  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h   |  2 +-
> > > >  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h      |  2 +-
> > > >  6 files changed, 35 insertions(+), 32 deletions(-)
> > >
> > > With this patch applied, I get the following crash on the Sony Xperia 1 III, a
> > > dual-DSI dual-DSC device:
> > >
> > >       Unable to handle kernel NULL pointer dereference at virtual address 0000000000000020
> > >       Mem abort info:
> > >         ESR = 0x0000000096000004
> > >         EC = 0x25: DABT (current EL), IL = 32 bits
> > >         SET = 0, FnV = 0
> > >         EA = 0, S1PTW = 0
> > >         FSC = 0x04: level 0 translation fault
> > >       Data abort info:
> > >         ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000
> > >         CM = 0, WnR = 0, TnD = 0, TagAccess = 0
> > >         GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
> > >       user pgtable: 4k pages, 48-bit VAs, pgdp=000000012d4e1000
> > >       [0000000000000020] pgd=0000000000000000, p4d=0000000000000000
> > >       Internal error: Oops: 0000000096000004 [#1]  SMP
> > >       Modules linked in: msm drm_client_lib ubwc_config drm_dp_aux_bus gpu_sched drm_gpuvm drm_exec
> > >       CPU: 5 UID: 0 PID: 3081 Comm: (sd-close) Tainted: G     U              6.18.0-rc7-next-20251127-SoMainline-12422-g10b6db5b056d-dirty #21 NONE
> > >       Tainted: [U]=USER
> > >       Hardware name: Sony Xperia 1 III (DT)
> > >       pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
> > >       pc : dpu_plane_atomic_check_sspp.isra.0+0x88/0x3f4 [msm]
> > >       lr : dpu_plane_atomic_check_sspp.isra.0+0x84/0x3f4 [msm]
> > >       sp : ffff800081e23940
> > >       x29: ffff800081e23950 x28: ffff0000bf2700d0 x27: 0000000000000a00
> > >       x26: ffff0000bf270000 x25: 0000000000000a00 x24: ffff0000bd0e5c18
> > >       x23: ffff000087a6c080 x22: 0000000000000224 x21: ffff00008ce88080
> > >       x20: 0000000000000002 x19: ffff0000bf270138 x18: ffff8000818350b0
> > >       x17: 000000040044ffff x16: ffffc488ae2e37e0 x15: 0000000000000005
> > >       x14: 0000000000000a00 x13: 0000000000000000 x12: 0000000000000138
> > >       x11: 0000000000000000 x10: 0000000000000012 x9 : 0000000000000000
> > >       x8 : 0000000000000a00 x7 : 0000000000000000 x6 : 0000000000000000
> > >       x5 : 0000000000000002 x4 : 0000000000000000 x3 : ffffc48897741db0
> > >       x2 : 0000000000000000 x1 : 0000000000000000 x0 : 0000000000000000
> > >       Call trace:
> > >        dpu_plane_atomic_check_sspp.isra.0+0x88/0x3f4 [msm] (P)
> > >        dpu_plane_atomic_check+0x100/0x1a0 [msm]
> > >        drm_atomic_helper_check_planes+0xd8/0x224
> > >        drm_atomic_helper_check+0x50/0xb4
> > >        msm_atomic_check+0xd0/0xe0 [msm]
> > >        drm_atomic_check_only+0x4e0/0x928
> > >        drm_atomic_commit+0x50/0xd4
> > >        drm_client_modeset_commit_atomic+0x200/0x260
> > >        drm_client_modeset_commit_locked+0x64/0x180
> > >        drm_client_modeset_commit+0x30/0x60
> > >        drm_fb_helper_lastclose+0x60/0xb0
> > >        drm_fbdev_client_restore+0x18/0x38 [drm_client_lib]
> > >        drm_client_dev_restore+0xac/0xf8
> > >        drm_release+0x124/0x158
> > >        __fput+0xd4/0x2e4
> > >        fput_close_sync+0x3c/0xe0
> > >        __arm64_sys_close+0x3c/0x84
> > >        invoke_syscall.constprop.0+0x44/0x100
> > >        el0_svc_common.constprop.0+0x3c/0xe4
> > >        do_el0_svc+0x20/0x3c
> > >        el0_svc+0x38/0x110
> > >        el0t_64_sync_handler+0xa8/0xec
> > >        el0t_64_sync+0x1a0/0x1a4
> > >       Code: 2a1403e5 52800082 94008e28 f9400380 (f940101b)
> > >       ---[ end trace 0000000000000000 ]---
> > >       pstore: backend (ramoops) writing error (-28)
> > >       [drm:dpu_encoder_frame_done_timeout:2726] [dpu error]enc33 frame done timeout
> > >
> > > I don't see any thought given to it in the extremely terse patch description,
> > > but this patch seems to unconditionally select 4 DSCs and 4 LMs on this device
> > > because the underlying SM8350 SoC has 4 available in its catalog - while it
> > > was previously affixed to 2:2:2 matching the downstream and known-working
> > > configuration of this device - and I can only imagine things are rolling
> > > downhill from there.
> > >
> > > faddr2line seems to be failing for me, but this is the line
> > > `dpu_plane_atomic_check_sspp.isra.0+0x88` seems to be referring to:
> > >
> > >       aarch64-linux-gnu-objdump .output/drivers/gpu/drm/msm/msm.ko -dS | grep dpu_plane_atomic_check_sspp.isra.0\> -A80
> > >       00000000000671ac <dpu_plane_atomic_check_sspp.isra.0>:
> > >       static int dpu_plane_atomic_check_sspp(struct drm_plane *plane,
> > >       ...
> > >          67234:       f940101b        ldr     x27, [x0, #32]
> > >               if (!(sblk->scaler_blk.len && pipe->sspp->ops.setup_scaler) &&
> >
> > I think it is:
> >
> >         pipe_hw_caps = pipe->sspp->cap;
> >     14bc:       f9401018        ldr     x24, [x0, #32]
> >
> >
> > So, please check why pipe->sspp becomes NULL (or where do we miss the
> > NULL check for pipe->sspp).
> 
> Yeah, per panic log and objdump, it should be due to this line. But no
> clue is found
> with code analysis.
> Did you reproduce it? If so, what's the platform and git commit id? I
> tested with
> HDK8650 dual-DSI HDMI bridged monitor, but kernel does not panic.
> 
> resource mapping:
>         pingpong=104 104 # # # # - - # # # # -
>         mixer=104 104 # # # # - -
>         ctl=104 # # # # # - -
>         dspp=# # # # - - - -
>         dsc=# # # # # # - -

This series, and specifically this patch I am replying to applies modifications
to DSC topology requests.  your test setup however does not seem to be using any
DSC encoders at all and is hence not going into this strange block of code that
I am concerned about:

	if (topology.num_dsc) {
		if (dpu_kms->catalog->dsc_count >= num_rt_intf * 2)
			topology.num_dsc = num_rt_intf * 2;
		else
			topology.num_dsc = num_rt_intf;
		topology.num_lm = topology.num_dsc;

For DSC-enabled setups with 2:2:2 topology (the device I mentioned in the
main report) this is bumping the number of DSC encoders **and layer mixers**
to **four** if available in the catalog; it is not even checked against the
currently allocated resources in the case of "hotpluggable" panels.

Unrelated to this bug, but as a relevant context-comment on this series:
We discussed scenarios in the past where DSC-merge might be used (for example
in a 2:2:1 or 4:4:2 topology) for improved power consumption, but should modeset
back to lower DSC usage (1:1:1 or 2:2:2) if a second display is plugged in that
also requires a DSC encoder to be driven at some refresh rate - and only 2 or 4
encoders are available.

- Marijn

>         cdm=#
>         sspp=# # # # - - - - 104 # # # # # - -
>         cwb=# # # #
> 
> 
> Hi Marijn,
> Could you help collect debug info with this change? Thanks!
> BTW: my irc id: niej
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> index d07a6ab6e7ee1..fc61c2fbb0699 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> @@ -886,6 +886,7 @@ static int dpu_plane_atomic_check_nosspp(struct
> drm_plane *plane,
>                         new_plane_state->fb->width, new_plane_state->fb->height,
>                         new_plane_state->rotation);
> 
> +       memset(&pstate->pipe_cfg[0], 0, PIPES_PER_PLANE *
> sizeof(struct dpu_sw_pipe_cfg));
>         /*
>          * We have 1 mixer pair cfg for 1:1:1 and 2:2:1 topology, 2 mixer pair
>          * configs for left and right half screen in case of 4:4:2 topology.
> @@ -1055,6 +1056,13 @@ static int dpu_plane_atomic_check_sspp(struct
> drm_plane *plane,
>                 if (!drm_rect_width(&pipe_cfg->src_rect))
>                         continue;
>                 DPU_DEBUG_PLANE(pdpu, "pipe %d is in use, validate it\n", i);
> +               if(!pipe->sspp) {
> +                       WARN(1, "%svirtual plane pipe %d is null with
> width %d height %d!!\n",
> +                               dpu_use_virtual_planes ? " " : "non-",
> +                               i,
> +                               drm_rect_width(&pipe_cfg->src_rect),
> +                               drm_rect_height(&pipe_cfg->src_rect));
> +               }
>                 ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg,
>                                                   &crtc_state->adjusted_mode,
>                                                   new_plane_state);
> >
> >
> > --
> > With best wishes
> > Dmitry

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v16 09/10] drm/msm/dpu: support plane splitting in quad-pipe case
  2025-09-18 13:29 ` [PATCH v16 09/10] drm/msm/dpu: support plane splitting in " Jun Nie
  2025-12-18 12:44   ` Abel Vesa
@ 2026-01-14 14:48   ` Jun Nie
  2026-01-14 16:12     ` Dmitry Baryshkov
  1 sibling, 1 reply; 28+ messages in thread
From: Jun Nie @ 2026-01-14 14:48 UTC (permalink / raw)
  To: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, Jessica Zhang
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel

Jun Nie <jun.nie@linaro.org> 于2025年9月18日周四 21:30写道:
>
> The content of every half of screen is sent out via one interface in
> dual-DSI case. The content for every interface is blended by a LM
> pair in quad-pipe case, thus a LM pair should not blend any content
> that cross the half of screen in this case. Clip plane into pipes per
> left and right half screen ROI if topology is quad pipe case.
>
> The clipped rectangle on every half of screen is futher handled by two
> pipes if its width exceeds a limit for a single pipe.
>
> Signed-off-by: Jun Nie <jun.nie@linaro.org>
> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> Reviewed-by: Jessica Zhang <jessica.zhang@oss.qualcomm.com>
> ---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c  |  11 +++
>  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h  |   2 +
>  drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 137 +++++++++++++++++++++---------
>  3 files changed, 110 insertions(+), 40 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> index d825eb8e40ae8bd456ede6269951339e3053d0d3..e925d93b38feac0594d735fdc2c5b9fd5ae83e6a 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> @@ -1604,6 +1604,17 @@ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en)
>         return 0;
>  }
>
> +/**
> + * dpu_crtc_get_num_lm - Get mixer number in this CRTC pipeline
> + * @state: Pointer to drm crtc state object
> + */
> +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state)
> +{
> +       struct dpu_crtc_state *cstate = to_dpu_crtc_state(state);
> +
> +       return cstate->num_mixers;
> +}
> +
>  #ifdef CONFIG_DEBUG_FS
>  static int _dpu_debugfs_status_show(struct seq_file *s, void *data)
>  {
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> index 94392b9b924546f96e738ae20920cf9afd568e6b..6eaba5696e8e6bd1246a9895c4c8714ca6589b10 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> @@ -267,4 +267,6 @@ static inline enum dpu_crtc_client_type dpu_crtc_get_client_type(
>
>  void dpu_crtc_frame_event_cb(struct drm_crtc *crtc, u32 event);
>
> +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state);
> +
>  #endif /* _DPU_CRTC_H_ */
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> index 5ae58352cbee1251a0140879f04fc7c304cae674..89a5feb6308bcac537562c3dc4e61c16c92e460c 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> @@ -824,8 +824,12 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
>         struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state);
>         struct dpu_sw_pipe_cfg *pipe_cfg;
>         struct dpu_sw_pipe_cfg *r_pipe_cfg;
> +       struct dpu_sw_pipe_cfg init_pipe_cfg;
>         struct drm_rect fb_rect = { 0 };
> +       const struct drm_display_mode *mode = &crtc_state->adjusted_mode;
>         uint32_t max_linewidth;
> +       u32 num_lm;
> +       int stage_id, num_stages;
>
>         min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
>         max_scale = MAX_DOWNSCALE_RATIO << 16;
> @@ -848,13 +852,10 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
>                 return -EINVAL;
>         }
>
> -       /* move the assignment here, to ease handling to another pairs later */
> -       pipe_cfg = &pstate->pipe_cfg[0];
> -       r_pipe_cfg = &pstate->pipe_cfg[1];
> -       /* state->src is 16.16, src_rect is not */
> -       drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src);
> +       num_lm = dpu_crtc_get_num_lm(crtc_state);
>
> -       pipe_cfg->dst_rect = new_plane_state->dst;
> +       /* state->src is 16.16, src_rect is not */
> +       drm_rect_fp_to_int(&init_pipe_cfg.src_rect, &new_plane_state->src);
>
>         fb_rect.x2 = new_plane_state->fb->width;
>         fb_rect.y2 = new_plane_state->fb->height;
> @@ -879,35 +880,94 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
>
>         max_linewidth = pdpu->catalog->caps->max_linewidth;
>
> -       drm_rect_rotate(&pipe_cfg->src_rect,
> +       drm_rect_rotate(&init_pipe_cfg.src_rect,
>                         new_plane_state->fb->width, new_plane_state->fb->height,
>                         new_plane_state->rotation);
>
> -       if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) ||
> -            _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) {
> -               if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) {
> -                       DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n",
> -                                       DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);
> -                       return -E2BIG;
> +       /*
> +        * We have 1 mixer pair cfg for 1:1:1 and 2:2:1 topology, 2 mixer pair
> +        * configs for left and right half screen in case of 4:4:2 topology.
> +        * But we may have 2 rect to split wide plane that exceeds limit with 1
> +        * config for 2:2:1. So need to handle both wide plane splitting, and
> +        * two halves of screen splitting for quad-pipe case. Check dest
> +        * rectangle left/right clipping first, then check wide rectangle
> +        * splitting in every half next.
> +        */
> +       num_stages = (num_lm + 1) / 2;

Hi Dmitry,
Because the plane is checked before crtc is checked in the drm framework. While
the topology is decided in crtc check. Thus num_lm is 0 when this function is
called for the first time. As a result, the below iteration is not run
at all and leads
 to iommu warning.
Do you suggest to change drm framework with adding extra crtc check before
plane check, or you prefer the below line here?

num_stages = max(1, (num_lm + 1) / 2);

Jun

> +       /* iterate mixer configs for this plane, to separate left/right with the id */
> +       for (stage_id = 0; stage_id < num_stages; stage_id++) {
> +               struct drm_rect mixer_rect = {
> +                       .x1 = stage_id * mode->hdisplay / num_stages,
> +                       .y1 = 0,
> +                       .x2 = (stage_id + 1) * mode->hdisplay / num_stages,
> +                       .y2 = mode->vdisplay
> +                       };
> +               int cfg_idx = stage_id * PIPES_PER_STAGE;
> +
> +               pipe_cfg = &pstate->pipe_cfg[cfg_idx];
> +               r_pipe_cfg = &pstate->pipe_cfg[cfg_idx + 1];
> +
> +               drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src);
> +               pipe_cfg->dst_rect = new_plane_state->dst;
> +
> +               DPU_DEBUG_PLANE(pdpu, "checking src " DRM_RECT_FMT
> +                               " vs clip window " DRM_RECT_FMT "\n",
> +                               DRM_RECT_ARG(&pipe_cfg->src_rect),
> +                               DRM_RECT_ARG(&mixer_rect));
> +
> +               /*
> +                * If this plane does not fall into mixer rect, check next
> +                * mixer rect.
> +                */
> +               if (!drm_rect_clip_scaled(&pipe_cfg->src_rect,
> +                                         &pipe_cfg->dst_rect,
> +                                         &mixer_rect)) {
> +                       memset(pipe_cfg, 0, 2 * sizeof(struct dpu_sw_pipe_cfg));
> +
> +                       continue;
>                 }
>
> -               *r_pipe_cfg = *pipe_cfg;
> -               pipe_cfg->src_rect.x2 = (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2) >> 1;
> -               pipe_cfg->dst_rect.x2 = (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2) >> 1;
> -               r_pipe_cfg->src_rect.x1 = pipe_cfg->src_rect.x2;
> -               r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2;
> -       } else {
> -               memset(r_pipe_cfg, 0, sizeof(*r_pipe_cfg));
> -       }
> +               pipe_cfg->dst_rect.x1 -= mixer_rect.x1;
> +               pipe_cfg->dst_rect.x2 -= mixer_rect.x1;
> +
> +               DPU_DEBUG_PLANE(pdpu, "Got clip src:" DRM_RECT_FMT " dst: " DRM_RECT_FMT "\n",
> +                               DRM_RECT_ARG(&pipe_cfg->src_rect), DRM_RECT_ARG(&pipe_cfg->dst_rect));
> +
> +               /* Split wide rect into 2 rect */
> +               if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) ||
> +                    _dpu_plane_calc_clk(mode, pipe_cfg) > max_mdp_clk_rate) {
> +
> +                       if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) {
> +                               DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n",
> +                                               DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);
> +                               return -E2BIG;
> +                       }
> +
> +                       memcpy(r_pipe_cfg, pipe_cfg, sizeof(struct dpu_sw_pipe_cfg));
> +                       pipe_cfg->src_rect.x2 = (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2) >> 1;
> +                       pipe_cfg->dst_rect.x2 = (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2) >> 1;
> +                       r_pipe_cfg->src_rect.x1 = pipe_cfg->src_rect.x2;
> +                       r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2;
> +                       DPU_DEBUG_PLANE(pdpu, "Split wide plane into:"
> +                                       DRM_RECT_FMT " and " DRM_RECT_FMT "\n",
> +                                       DRM_RECT_ARG(&pipe_cfg->src_rect),
> +                                       DRM_RECT_ARG(&r_pipe_cfg->src_rect));
> +               } else {
> +                       memset(r_pipe_cfg, 0, sizeof(struct dpu_sw_pipe_cfg));
> +               }
>
> -       drm_rect_rotate_inv(&pipe_cfg->src_rect,
> -                           new_plane_state->fb->width, new_plane_state->fb->height,
> -                           new_plane_state->rotation);
> -       if (drm_rect_width(&r_pipe_cfg->src_rect) != 0)
> -               drm_rect_rotate_inv(&r_pipe_cfg->src_rect,
> -                                   new_plane_state->fb->width, new_plane_state->fb->height,
> +               drm_rect_rotate_inv(&pipe_cfg->src_rect,
> +                                   new_plane_state->fb->width,
> +                                   new_plane_state->fb->height,
>                                     new_plane_state->rotation);
>
> +               if (drm_rect_width(&r_pipe_cfg->src_rect) != 0)
> +                       drm_rect_rotate_inv(&r_pipe_cfg->src_rect,
> +                                           new_plane_state->fb->width,
> +                                           new_plane_state->fb->height,
> +                                           new_plane_state->rotation);
> +       }
> +
>         pstate->needs_qos_remap = drm_atomic_crtc_needs_modeset(crtc_state);
>
>         return 0;
> @@ -983,20 +1043,17 @@ static int dpu_plane_atomic_check_sspp(struct drm_plane *plane,
>                 drm_atomic_get_new_plane_state(state, plane);
>         struct dpu_plane *pdpu = to_dpu_plane(plane);
>         struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state);
> -       struct dpu_sw_pipe *pipe = &pstate->pipe[0];
> -       struct dpu_sw_pipe *r_pipe = &pstate->pipe[1];
> -       struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg[0];
> -       struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->pipe_cfg[1];
> -       int ret = 0;
> -
> -       ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg,
> -                                         &crtc_state->adjusted_mode,
> -                                         new_plane_state);
> -       if (ret)
> -               return ret;
> +       struct dpu_sw_pipe *pipe;
> +       struct dpu_sw_pipe_cfg *pipe_cfg;
> +       int ret = 0, i;
>
> -       if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) {
> -               ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg,
> +       for (i = 0; i < PIPES_PER_PLANE; i++) {
> +               pipe = &pstate->pipe[i];
> +               pipe_cfg = &pstate->pipe_cfg[i];
> +               if (!drm_rect_width(&pipe_cfg->src_rect))
> +                       continue;
> +               DPU_DEBUG_PLANE(pdpu, "pipe %d is in use, validate it\n", i);
> +               ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg,
>                                                   &crtc_state->adjusted_mode,
>                                                   new_plane_state);
>                 if (ret)
>
> --
> 2.34.1
>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v16 09/10] drm/msm/dpu: support plane splitting in quad-pipe case
  2026-01-14 14:48   ` Jun Nie
@ 2026-01-14 16:12     ` Dmitry Baryshkov
  2026-01-15  9:34       ` Jun Nie
  0 siblings, 1 reply; 28+ messages in thread
From: Dmitry Baryshkov @ 2026-01-14 16:12 UTC (permalink / raw)
  To: Jun Nie
  Cc: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, Jessica Zhang,
	linux-arm-msm, dri-devel, freedreno, linux-kernel

On Wed, Jan 14, 2026 at 10:48:17PM +0800, Jun Nie wrote:
> Jun Nie <jun.nie@linaro.org> 于2025年9月18日周四 21:30写道:
> >
> > The content of every half of screen is sent out via one interface in
> > dual-DSI case. The content for every interface is blended by a LM
> > pair in quad-pipe case, thus a LM pair should not blend any content
> > that cross the half of screen in this case. Clip plane into pipes per
> > left and right half screen ROI if topology is quad pipe case.
> >
> > The clipped rectangle on every half of screen is futher handled by two
> > pipes if its width exceeds a limit for a single pipe.
> >
> > Signed-off-by: Jun Nie <jun.nie@linaro.org>
> > Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > Reviewed-by: Jessica Zhang <jessica.zhang@oss.qualcomm.com>
> > ---
> >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c  |  11 +++
> >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h  |   2 +
> >  drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 137 +++++++++++++++++++++---------
> >  3 files changed, 110 insertions(+), 40 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > index d825eb8e40ae8bd456ede6269951339e3053d0d3..e925d93b38feac0594d735fdc2c5b9fd5ae83e6a 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > @@ -1604,6 +1604,17 @@ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en)
> >         return 0;
> >  }
> >
> > +/**
> > + * dpu_crtc_get_num_lm - Get mixer number in this CRTC pipeline
> > + * @state: Pointer to drm crtc state object
> > + */
> > +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state)
> > +{
> > +       struct dpu_crtc_state *cstate = to_dpu_crtc_state(state);
> > +
> > +       return cstate->num_mixers;
> > +}
> > +
> >  #ifdef CONFIG_DEBUG_FS
> >  static int _dpu_debugfs_status_show(struct seq_file *s, void *data)
> >  {
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > index 94392b9b924546f96e738ae20920cf9afd568e6b..6eaba5696e8e6bd1246a9895c4c8714ca6589b10 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > @@ -267,4 +267,6 @@ static inline enum dpu_crtc_client_type dpu_crtc_get_client_type(
> >
> >  void dpu_crtc_frame_event_cb(struct drm_crtc *crtc, u32 event);
> >
> > +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state);
> > +
> >  #endif /* _DPU_CRTC_H_ */
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > index 5ae58352cbee1251a0140879f04fc7c304cae674..89a5feb6308bcac537562c3dc4e61c16c92e460c 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > @@ -824,8 +824,12 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
> >         struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state);
> >         struct dpu_sw_pipe_cfg *pipe_cfg;
> >         struct dpu_sw_pipe_cfg *r_pipe_cfg;
> > +       struct dpu_sw_pipe_cfg init_pipe_cfg;
> >         struct drm_rect fb_rect = { 0 };
> > +       const struct drm_display_mode *mode = &crtc_state->adjusted_mode;
> >         uint32_t max_linewidth;
> > +       u32 num_lm;
> > +       int stage_id, num_stages;
> >
> >         min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
> >         max_scale = MAX_DOWNSCALE_RATIO << 16;
> > @@ -848,13 +852,10 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
> >                 return -EINVAL;
> >         }
> >
> > -       /* move the assignment here, to ease handling to another pairs later */
> > -       pipe_cfg = &pstate->pipe_cfg[0];
> > -       r_pipe_cfg = &pstate->pipe_cfg[1];
> > -       /* state->src is 16.16, src_rect is not */
> > -       drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src);
> > +       num_lm = dpu_crtc_get_num_lm(crtc_state);
> >
> > -       pipe_cfg->dst_rect = new_plane_state->dst;
> > +       /* state->src is 16.16, src_rect is not */
> > +       drm_rect_fp_to_int(&init_pipe_cfg.src_rect, &new_plane_state->src);
> >
> >         fb_rect.x2 = new_plane_state->fb->width;
> >         fb_rect.y2 = new_plane_state->fb->height;
> > @@ -879,35 +880,94 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
> >
> >         max_linewidth = pdpu->catalog->caps->max_linewidth;
> >
> > -       drm_rect_rotate(&pipe_cfg->src_rect,
> > +       drm_rect_rotate(&init_pipe_cfg.src_rect,
> >                         new_plane_state->fb->width, new_plane_state->fb->height,
> >                         new_plane_state->rotation);
> >
> > -       if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) ||
> > -            _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) {
> > -               if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) {
> > -                       DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n",
> > -                                       DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);
> > -                       return -E2BIG;
> > +       /*
> > +        * We have 1 mixer pair cfg for 1:1:1 and 2:2:1 topology, 2 mixer pair
> > +        * configs for left and right half screen in case of 4:4:2 topology.
> > +        * But we may have 2 rect to split wide plane that exceeds limit with 1
> > +        * config for 2:2:1. So need to handle both wide plane splitting, and
> > +        * two halves of screen splitting for quad-pipe case. Check dest
> > +        * rectangle left/right clipping first, then check wide rectangle
> > +        * splitting in every half next.
> > +        */
> > +       num_stages = (num_lm + 1) / 2;
> 
> Hi Dmitry,
> Because the plane is checked before crtc is checked in the drm framework. While
> the topology is decided in crtc check. Thus num_lm is 0 when this function is
> called for the first time. As a result, the below iteration is not run
> at all and leads
>  to iommu warning.

How does it lead to IOMMU warnings?

> Do you suggest to change drm framework with adding extra crtc check before
> plane check, or you prefer the below line here?
> 
> num_stages = max(1, (num_lm + 1) / 2);

DRM framework provides enough hooks to be able to influence the order or
operations without changing the framework. But, I'd like to point out
that for the virtual plane case we already perform plane operations
from dpu_crtc_atomic_check(). You can employ the same approach.


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v16 09/10] drm/msm/dpu: support plane splitting in quad-pipe case
  2026-01-14 16:12     ` Dmitry Baryshkov
@ 2026-01-15  9:34       ` Jun Nie
  2026-01-15  9:38         ` Dmitry Baryshkov
  0 siblings, 1 reply; 28+ messages in thread
From: Jun Nie @ 2026-01-15  9:34 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, Jessica Zhang,
	linux-arm-msm, dri-devel, freedreno, linux-kernel

Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> 于2026年1月15日周四 00:12写道:
>
> On Wed, Jan 14, 2026 at 10:48:17PM +0800, Jun Nie wrote:
> > Jun Nie <jun.nie@linaro.org> 于2025年9月18日周四 21:30写道:
> > >
> > > The content of every half of screen is sent out via one interface in
> > > dual-DSI case. The content for every interface is blended by a LM
> > > pair in quad-pipe case, thus a LM pair should not blend any content
> > > that cross the half of screen in this case. Clip plane into pipes per
> > > left and right half screen ROI if topology is quad pipe case.
> > >
> > > The clipped rectangle on every half of screen is futher handled by two
> > > pipes if its width exceeds a limit for a single pipe.
> > >
> > > Signed-off-by: Jun Nie <jun.nie@linaro.org>
> > > Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > Reviewed-by: Jessica Zhang <jessica.zhang@oss.qualcomm.com>
> > > ---
> > >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c  |  11 +++
> > >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h  |   2 +
> > >  drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 137 +++++++++++++++++++++---------
> > >  3 files changed, 110 insertions(+), 40 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > index d825eb8e40ae8bd456ede6269951339e3053d0d3..e925d93b38feac0594d735fdc2c5b9fd5ae83e6a 100644
> > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > @@ -1604,6 +1604,17 @@ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en)
> > >         return 0;
> > >  }
> > >
> > > +/**
> > > + * dpu_crtc_get_num_lm - Get mixer number in this CRTC pipeline
> > > + * @state: Pointer to drm crtc state object
> > > + */
> > > +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state)
> > > +{
> > > +       struct dpu_crtc_state *cstate = to_dpu_crtc_state(state);
> > > +
> > > +       return cstate->num_mixers;
> > > +}
> > > +
> > >  #ifdef CONFIG_DEBUG_FS
> > >  static int _dpu_debugfs_status_show(struct seq_file *s, void *data)
> > >  {
> > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > > index 94392b9b924546f96e738ae20920cf9afd568e6b..6eaba5696e8e6bd1246a9895c4c8714ca6589b10 100644
> > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > > @@ -267,4 +267,6 @@ static inline enum dpu_crtc_client_type dpu_crtc_get_client_type(
> > >
> > >  void dpu_crtc_frame_event_cb(struct drm_crtc *crtc, u32 event);
> > >
> > > +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state);
> > > +
> > >  #endif /* _DPU_CRTC_H_ */
> > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > index 5ae58352cbee1251a0140879f04fc7c304cae674..89a5feb6308bcac537562c3dc4e61c16c92e460c 100644
> > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > @@ -824,8 +824,12 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
> > >         struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state);
> > >         struct dpu_sw_pipe_cfg *pipe_cfg;
> > >         struct dpu_sw_pipe_cfg *r_pipe_cfg;
> > > +       struct dpu_sw_pipe_cfg init_pipe_cfg;
> > >         struct drm_rect fb_rect = { 0 };
> > > +       const struct drm_display_mode *mode = &crtc_state->adjusted_mode;
> > >         uint32_t max_linewidth;
> > > +       u32 num_lm;
> > > +       int stage_id, num_stages;
> > >
> > >         min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
> > >         max_scale = MAX_DOWNSCALE_RATIO << 16;
> > > @@ -848,13 +852,10 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
> > >                 return -EINVAL;
> > >         }
> > >
> > > -       /* move the assignment here, to ease handling to another pairs later */
> > > -       pipe_cfg = &pstate->pipe_cfg[0];
> > > -       r_pipe_cfg = &pstate->pipe_cfg[1];
> > > -       /* state->src is 16.16, src_rect is not */
> > > -       drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src);
> > > +       num_lm = dpu_crtc_get_num_lm(crtc_state);
> > >
> > > -       pipe_cfg->dst_rect = new_plane_state->dst;
> > > +       /* state->src is 16.16, src_rect is not */
> > > +       drm_rect_fp_to_int(&init_pipe_cfg.src_rect, &new_plane_state->src);
> > >
> > >         fb_rect.x2 = new_plane_state->fb->width;
> > >         fb_rect.y2 = new_plane_state->fb->height;
> > > @@ -879,35 +880,94 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
> > >
> > >         max_linewidth = pdpu->catalog->caps->max_linewidth;
> > >
> > > -       drm_rect_rotate(&pipe_cfg->src_rect,
> > > +       drm_rect_rotate(&init_pipe_cfg.src_rect,
> > >                         new_plane_state->fb->width, new_plane_state->fb->height,
> > >                         new_plane_state->rotation);
> > >
> > > -       if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) ||
> > > -            _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) {
> > > -               if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) {
> > > -                       DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n",
> > > -                                       DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);
> > > -                       return -E2BIG;
> > > +       /*
> > > +        * We have 1 mixer pair cfg for 1:1:1 and 2:2:1 topology, 2 mixer pair
> > > +        * configs for left and right half screen in case of 4:4:2 topology.
> > > +        * But we may have 2 rect to split wide plane that exceeds limit with 1
> > > +        * config for 2:2:1. So need to handle both wide plane splitting, and
> > > +        * two halves of screen splitting for quad-pipe case. Check dest
> > > +        * rectangle left/right clipping first, then check wide rectangle
> > > +        * splitting in every half next.
> > > +        */
> > > +       num_stages = (num_lm + 1) / 2;
> >
> > Hi Dmitry,
> > Because the plane is checked before crtc is checked in the drm framework. While
> > the topology is decided in crtc check. Thus num_lm is 0 when this function is
> > called for the first time. As a result, the below iteration is not run
> > at all and leads
> >  to iommu warning.
>
> How does it lead to IOMMU warnings?

Because the pipe is not configured with width/height etc when the iteration is
skipped. I have not found the root cause so far. But per the null IOMMU iova
value, suppose it is due to DMA buffer not being prepared when DMA is started.

>
> > Do you suggest to change drm framework with adding extra crtc check before
> > plane check, or you prefer the below line here?
> >
> > num_stages = max(1, (num_lm + 1) / 2);
>
> DRM framework provides enough hooks to be able to influence the order or
> operations without changing the framework. But, I'd like to point out
> that for the virtual plane case we already perform plane operations
> from dpu_crtc_atomic_check(). You can employ the same approach.

Thanks for the suggestion! I see dpu_assign_plane_resources() is called
from crtc side, which avoids the plane splitting before topology decision.
To use this method, it looks like we are enabling the virtual plane by default.
Because the virtual plane differs from the traditional method only with the
plane splitting and resource preparation. Can we just enable the virtual
plane by default in this situation?

Jun

>
>
> --
> With best wishes
> Dmitry

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v16 09/10] drm/msm/dpu: support plane splitting in quad-pipe case
  2026-01-15  9:34       ` Jun Nie
@ 2026-01-15  9:38         ` Dmitry Baryshkov
  2026-01-15  9:57           ` Jun Nie
  0 siblings, 1 reply; 28+ messages in thread
From: Dmitry Baryshkov @ 2026-01-15  9:38 UTC (permalink / raw)
  To: Jun Nie
  Cc: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, Jessica Zhang,
	linux-arm-msm, dri-devel, freedreno, linux-kernel

On Thu, Jan 15, 2026 at 05:34:28PM +0800, Jun Nie wrote:
> Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> 于2026年1月15日周四 00:12写道:
> >
> > On Wed, Jan 14, 2026 at 10:48:17PM +0800, Jun Nie wrote:
> > > Jun Nie <jun.nie@linaro.org> 于2025年9月18日周四 21:30写道:
> > > >
> > > > The content of every half of screen is sent out via one interface in
> > > > dual-DSI case. The content for every interface is blended by a LM
> > > > pair in quad-pipe case, thus a LM pair should not blend any content
> > > > that cross the half of screen in this case. Clip plane into pipes per
> > > > left and right half screen ROI if topology is quad pipe case.
> > > >
> > > > The clipped rectangle on every half of screen is futher handled by two
> > > > pipes if its width exceeds a limit for a single pipe.
> > > >
> > > > Signed-off-by: Jun Nie <jun.nie@linaro.org>
> > > > Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > Reviewed-by: Jessica Zhang <jessica.zhang@oss.qualcomm.com>
> > > > ---
> > > >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c  |  11 +++
> > > >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h  |   2 +
> > > >  drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 137 +++++++++++++++++++++---------
> > > >  3 files changed, 110 insertions(+), 40 deletions(-)
> > > >
> > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > index d825eb8e40ae8bd456ede6269951339e3053d0d3..e925d93b38feac0594d735fdc2c5b9fd5ae83e6a 100644
> > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > @@ -1604,6 +1604,17 @@ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en)
> > > >         return 0;
> > > >  }
> > > >
> > > > +/**
> > > > + * dpu_crtc_get_num_lm - Get mixer number in this CRTC pipeline
> > > > + * @state: Pointer to drm crtc state object
> > > > + */
> > > > +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state)
> > > > +{
> > > > +       struct dpu_crtc_state *cstate = to_dpu_crtc_state(state);
> > > > +
> > > > +       return cstate->num_mixers;
> > > > +}
> > > > +
> > > >  #ifdef CONFIG_DEBUG_FS
> > > >  static int _dpu_debugfs_status_show(struct seq_file *s, void *data)
> > > >  {
> > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > > > index 94392b9b924546f96e738ae20920cf9afd568e6b..6eaba5696e8e6bd1246a9895c4c8714ca6589b10 100644
> > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > > > @@ -267,4 +267,6 @@ static inline enum dpu_crtc_client_type dpu_crtc_get_client_type(
> > > >
> > > >  void dpu_crtc_frame_event_cb(struct drm_crtc *crtc, u32 event);
> > > >
> > > > +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state);
> > > > +
> > > >  #endif /* _DPU_CRTC_H_ */
> > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > index 5ae58352cbee1251a0140879f04fc7c304cae674..89a5feb6308bcac537562c3dc4e61c16c92e460c 100644
> > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > @@ -824,8 +824,12 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
> > > >         struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state);
> > > >         struct dpu_sw_pipe_cfg *pipe_cfg;
> > > >         struct dpu_sw_pipe_cfg *r_pipe_cfg;
> > > > +       struct dpu_sw_pipe_cfg init_pipe_cfg;
> > > >         struct drm_rect fb_rect = { 0 };
> > > > +       const struct drm_display_mode *mode = &crtc_state->adjusted_mode;
> > > >         uint32_t max_linewidth;
> > > > +       u32 num_lm;
> > > > +       int stage_id, num_stages;
> > > >
> > > >         min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
> > > >         max_scale = MAX_DOWNSCALE_RATIO << 16;
> > > > @@ -848,13 +852,10 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
> > > >                 return -EINVAL;
> > > >         }
> > > >
> > > > -       /* move the assignment here, to ease handling to another pairs later */
> > > > -       pipe_cfg = &pstate->pipe_cfg[0];
> > > > -       r_pipe_cfg = &pstate->pipe_cfg[1];
> > > > -       /* state->src is 16.16, src_rect is not */
> > > > -       drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src);
> > > > +       num_lm = dpu_crtc_get_num_lm(crtc_state);
> > > >
> > > > -       pipe_cfg->dst_rect = new_plane_state->dst;
> > > > +       /* state->src is 16.16, src_rect is not */
> > > > +       drm_rect_fp_to_int(&init_pipe_cfg.src_rect, &new_plane_state->src);
> > > >
> > > >         fb_rect.x2 = new_plane_state->fb->width;
> > > >         fb_rect.y2 = new_plane_state->fb->height;
> > > > @@ -879,35 +880,94 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
> > > >
> > > >         max_linewidth = pdpu->catalog->caps->max_linewidth;
> > > >
> > > > -       drm_rect_rotate(&pipe_cfg->src_rect,
> > > > +       drm_rect_rotate(&init_pipe_cfg.src_rect,
> > > >                         new_plane_state->fb->width, new_plane_state->fb->height,
> > > >                         new_plane_state->rotation);
> > > >
> > > > -       if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) ||
> > > > -            _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) {
> > > > -               if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) {
> > > > -                       DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n",
> > > > -                                       DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);
> > > > -                       return -E2BIG;
> > > > +       /*
> > > > +        * We have 1 mixer pair cfg for 1:1:1 and 2:2:1 topology, 2 mixer pair
> > > > +        * configs for left and right half screen in case of 4:4:2 topology.
> > > > +        * But we may have 2 rect to split wide plane that exceeds limit with 1
> > > > +        * config for 2:2:1. So need to handle both wide plane splitting, and
> > > > +        * two halves of screen splitting for quad-pipe case. Check dest
> > > > +        * rectangle left/right clipping first, then check wide rectangle
> > > > +        * splitting in every half next.
> > > > +        */
> > > > +       num_stages = (num_lm + 1) / 2;
> > >
> > > Hi Dmitry,
> > > Because the plane is checked before crtc is checked in the drm framework. While
> > > the topology is decided in crtc check. Thus num_lm is 0 when this function is
> > > called for the first time. As a result, the below iteration is not run
> > > at all and leads
> > >  to iommu warning.
> >
> > How does it lead to IOMMU warnings?
> 
> Because the pipe is not configured with width/height etc when the iteration is
> skipped. I have not found the root cause so far. But per the null IOMMU iova
> value, suppose it is due to DMA buffer not being prepared when DMA is started.

I'd think, that corresponding SRC regs are either garbage or zero programmed.

> 
> >
> > > Do you suggest to change drm framework with adding extra crtc check before
> > > plane check, or you prefer the below line here?
> > >
> > > num_stages = max(1, (num_lm + 1) / 2);
> >
> > DRM framework provides enough hooks to be able to influence the order or
> > operations without changing the framework. But, I'd like to point out
> > that for the virtual plane case we already perform plane operations
> > from dpu_crtc_atomic_check(). You can employ the same approach.
> 
> Thanks for the suggestion! I see dpu_assign_plane_resources() is called
> from crtc side, which avoids the plane splitting before topology decision.
> To use this method, it looks like we are enabling the virtual plane by default.
> Because the virtual plane differs from the traditional method only with the
> plane splitting and resource preparation. Can we just enable the virtual
> plane by default in this situation?

In which situation? It is a global switch. And we need to be able to
work with it turned off, until corresponding code is dropped.

> 
> Jun
> 
> >
> >
> > --
> > With best wishes
> > Dmitry

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v16 09/10] drm/msm/dpu: support plane splitting in quad-pipe case
  2026-01-15  9:38         ` Dmitry Baryshkov
@ 2026-01-15  9:57           ` Jun Nie
  2026-01-15 10:10             ` Jun Nie
  0 siblings, 1 reply; 28+ messages in thread
From: Jun Nie @ 2026-01-15  9:57 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, linux-arm-msm, dri-devel,
	freedreno, linux-kernel

Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> 于2026年1月15日周四 17:39写道:
>
> On Thu, Jan 15, 2026 at 05:34:28PM +0800, Jun Nie wrote:
> > Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> 于2026年1月15日周四 00:12写道:
> > >
> > > On Wed, Jan 14, 2026 at 10:48:17PM +0800, Jun Nie wrote:
> > > > Jun Nie <jun.nie@linaro.org> 于2025年9月18日周四 21:30写道:
> > > > >
> > > > > The content of every half of screen is sent out via one interface in
> > > > > dual-DSI case. The content for every interface is blended by a LM
> > > > > pair in quad-pipe case, thus a LM pair should not blend any content
> > > > > that cross the half of screen in this case. Clip plane into pipes per
> > > > > left and right half screen ROI if topology is quad pipe case.
> > > > >
> > > > > The clipped rectangle on every half of screen is futher handled by two
> > > > > pipes if its width exceeds a limit for a single pipe.
> > > > >
> > > > > Signed-off-by: Jun Nie <jun.nie@linaro.org>
> > > > > Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > > Reviewed-by: Jessica Zhang <jessica.zhang@oss.qualcomm.com>
> > > > > ---
> > > > >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c  |  11 +++
> > > > >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h  |   2 +
> > > > >  drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 137 +++++++++++++++++++++---------
> > > > >  3 files changed, 110 insertions(+), 40 deletions(-)
> > > > >
> > > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > > index d825eb8e40ae8bd456ede6269951339e3053d0d3..e925d93b38feac0594d735fdc2c5b9fd5ae83e6a 100644
> > > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > > @@ -1604,6 +1604,17 @@ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en)
> > > > >         return 0;
> > > > >  }
> > > > >
> > > > > +/**
> > > > > + * dpu_crtc_get_num_lm - Get mixer number in this CRTC pipeline
> > > > > + * @state: Pointer to drm crtc state object
> > > > > + */
> > > > > +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state)
> > > > > +{
> > > > > +       struct dpu_crtc_state *cstate = to_dpu_crtc_state(state);
> > > > > +
> > > > > +       return cstate->num_mixers;
> > > > > +}
> > > > > +
> > > > >  #ifdef CONFIG_DEBUG_FS
> > > > >  static int _dpu_debugfs_status_show(struct seq_file *s, void *data)
> > > > >  {
> > > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > > > > index 94392b9b924546f96e738ae20920cf9afd568e6b..6eaba5696e8e6bd1246a9895c4c8714ca6589b10 100644
> > > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > > > > @@ -267,4 +267,6 @@ static inline enum dpu_crtc_client_type dpu_crtc_get_client_type(
> > > > >
> > > > >  void dpu_crtc_frame_event_cb(struct drm_crtc *crtc, u32 event);
> > > > >
> > > > > +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state);
> > > > > +
> > > > >  #endif /* _DPU_CRTC_H_ */
> > > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > > index 5ae58352cbee1251a0140879f04fc7c304cae674..89a5feb6308bcac537562c3dc4e61c16c92e460c 100644
> > > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > > @@ -824,8 +824,12 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
> > > > >         struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state);
> > > > >         struct dpu_sw_pipe_cfg *pipe_cfg;
> > > > >         struct dpu_sw_pipe_cfg *r_pipe_cfg;
> > > > > +       struct dpu_sw_pipe_cfg init_pipe_cfg;
> > > > >         struct drm_rect fb_rect = { 0 };
> > > > > +       const struct drm_display_mode *mode = &crtc_state->adjusted_mode;
> > > > >         uint32_t max_linewidth;
> > > > > +       u32 num_lm;
> > > > > +       int stage_id, num_stages;
> > > > >
> > > > >         min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
> > > > >         max_scale = MAX_DOWNSCALE_RATIO << 16;
> > > > > @@ -848,13 +852,10 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
> > > > >                 return -EINVAL;
> > > > >         }
> > > > >
> > > > > -       /* move the assignment here, to ease handling to another pairs later */
> > > > > -       pipe_cfg = &pstate->pipe_cfg[0];
> > > > > -       r_pipe_cfg = &pstate->pipe_cfg[1];
> > > > > -       /* state->src is 16.16, src_rect is not */
> > > > > -       drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src);
> > > > > +       num_lm = dpu_crtc_get_num_lm(crtc_state);
> > > > >
> > > > > -       pipe_cfg->dst_rect = new_plane_state->dst;
> > > > > +       /* state->src is 16.16, src_rect is not */
> > > > > +       drm_rect_fp_to_int(&init_pipe_cfg.src_rect, &new_plane_state->src);
> > > > >
> > > > >         fb_rect.x2 = new_plane_state->fb->width;
> > > > >         fb_rect.y2 = new_plane_state->fb->height;
> > > > > @@ -879,35 +880,94 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
> > > > >
> > > > >         max_linewidth = pdpu->catalog->caps->max_linewidth;
> > > > >
> > > > > -       drm_rect_rotate(&pipe_cfg->src_rect,
> > > > > +       drm_rect_rotate(&init_pipe_cfg.src_rect,
> > > > >                         new_plane_state->fb->width, new_plane_state->fb->height,
> > > > >                         new_plane_state->rotation);
> > > > >
> > > > > -       if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) ||
> > > > > -            _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) {
> > > > > -               if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) {
> > > > > -                       DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n",
> > > > > -                                       DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);
> > > > > -                       return -E2BIG;
> > > > > +       /*
> > > > > +        * We have 1 mixer pair cfg for 1:1:1 and 2:2:1 topology, 2 mixer pair
> > > > > +        * configs for left and right half screen in case of 4:4:2 topology.
> > > > > +        * But we may have 2 rect to split wide plane that exceeds limit with 1
> > > > > +        * config for 2:2:1. So need to handle both wide plane splitting, and
> > > > > +        * two halves of screen splitting for quad-pipe case. Check dest
> > > > > +        * rectangle left/right clipping first, then check wide rectangle
> > > > > +        * splitting in every half next.
> > > > > +        */
> > > > > +       num_stages = (num_lm + 1) / 2;
> > > >
> > > > Hi Dmitry,
> > > > Because the plane is checked before crtc is checked in the drm framework. While
> > > > the topology is decided in crtc check. Thus num_lm is 0 when this function is
> > > > called for the first time. As a result, the below iteration is not run
> > > > at all and leads
> > > >  to iommu warning.
> > >
> > > How does it lead to IOMMU warnings?
> >
> > Because the pipe is not configured with width/height etc when the iteration is
> > skipped. I have not found the root cause so far. But per the null IOMMU iova
> > value, suppose it is due to DMA buffer not being prepared when DMA is started.
>
> I'd think, that corresponding SRC regs are either garbage or zero programmed.

You are right in that. Sorry for my words is not accurate. I mean the
DMA buffer is not
feed to DMA engine correctly.
>
> >
> > >
> > > > Do you suggest to change drm framework with adding extra crtc check before
> > > > plane check, or you prefer the below line here?
> > > >
> > > > num_stages = max(1, (num_lm + 1) / 2);
> > >
> > > DRM framework provides enough hooks to be able to influence the order or
> > > operations without changing the framework. But, I'd like to point out
> > > that for the virtual plane case we already perform plane operations
> > > from dpu_crtc_atomic_check(). You can employ the same approach.
> >
> > Thanks for the suggestion! I see dpu_assign_plane_resources() is called
> > from crtc side, which avoids the plane splitting before topology decision.
> > To use this method, it looks like we are enabling the virtual plane by default.
> > Because the virtual plane differs from the traditional method only with the
> > plane splitting and resource preparation. Can we just enable the virtual
> > plane by default in this situation?
>
> In which situation? It is a global switch. And we need to be able to
> work with it turned off, until corresponding code is dropped.

I mean the situation that the plane SSPP allocation and related resource
preparation shall be deferred until crtc calling the plane API. In this way,
the traditional plane management is almost identical with the virtual
plane method. Or could you point out what shall differ for the two methods
after we deferred the preparation? Thanks!

Jun
>
> >
> > Jun
> >
> > >
> > >
> > > --
> > > With best wishes
> > > Dmitry
>
> --
> With best wishes
> Dmitry

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v16 09/10] drm/msm/dpu: support plane splitting in quad-pipe case
  2026-01-15  9:57           ` Jun Nie
@ 2026-01-15 10:10             ` Jun Nie
  2026-01-15 18:36               ` Dmitry Baryshkov
  0 siblings, 1 reply; 28+ messages in thread
From: Jun Nie @ 2026-01-15 10:10 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, linux-arm-msm, dri-devel,
	freedreno, linux-kernel

Jun Nie <jun.nie@linaro.org> 于2026年1月15日周四 17:57写道:
>
> Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> 于2026年1月15日周四 17:39写道:
> >
> > On Thu, Jan 15, 2026 at 05:34:28PM +0800, Jun Nie wrote:
> > > Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> 于2026年1月15日周四 00:12写道:
> > > >
> > > > On Wed, Jan 14, 2026 at 10:48:17PM +0800, Jun Nie wrote:
> > > > > Jun Nie <jun.nie@linaro.org> 于2025年9月18日周四 21:30写道:
> > > > > >
> > > > > > The content of every half of screen is sent out via one interface in
> > > > > > dual-DSI case. The content for every interface is blended by a LM
> > > > > > pair in quad-pipe case, thus a LM pair should not blend any content
> > > > > > that cross the half of screen in this case. Clip plane into pipes per
> > > > > > left and right half screen ROI if topology is quad pipe case.
> > > > > >
> > > > > > The clipped rectangle on every half of screen is futher handled by two
> > > > > > pipes if its width exceeds a limit for a single pipe.
> > > > > >
> > > > > > Signed-off-by: Jun Nie <jun.nie@linaro.org>
> > > > > > Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > > > Reviewed-by: Jessica Zhang <jessica.zhang@oss.qualcomm.com>
> > > > > > ---
> > > > > >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c  |  11 +++
> > > > > >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h  |   2 +
> > > > > >  drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 137 +++++++++++++++++++++---------
> > > > > >  3 files changed, 110 insertions(+), 40 deletions(-)
> > > > > >
> > > > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > > > index d825eb8e40ae8bd456ede6269951339e3053d0d3..e925d93b38feac0594d735fdc2c5b9fd5ae83e6a 100644
> > > > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > > > @@ -1604,6 +1604,17 @@ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en)
> > > > > >         return 0;
> > > > > >  }
> > > > > >
> > > > > > +/**
> > > > > > + * dpu_crtc_get_num_lm - Get mixer number in this CRTC pipeline
> > > > > > + * @state: Pointer to drm crtc state object
> > > > > > + */
> > > > > > +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state)
> > > > > > +{
> > > > > > +       struct dpu_crtc_state *cstate = to_dpu_crtc_state(state);
> > > > > > +
> > > > > > +       return cstate->num_mixers;
> > > > > > +}
> > > > > > +
> > > > > >  #ifdef CONFIG_DEBUG_FS
> > > > > >  static int _dpu_debugfs_status_show(struct seq_file *s, void *data)
> > > > > >  {
> > > > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > > > > > index 94392b9b924546f96e738ae20920cf9afd568e6b..6eaba5696e8e6bd1246a9895c4c8714ca6589b10 100644
> > > > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > > > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > > > > > @@ -267,4 +267,6 @@ static inline enum dpu_crtc_client_type dpu_crtc_get_client_type(
> > > > > >
> > > > > >  void dpu_crtc_frame_event_cb(struct drm_crtc *crtc, u32 event);
> > > > > >
> > > > > > +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state);
> > > > > > +
> > > > > >  #endif /* _DPU_CRTC_H_ */
> > > > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > > > index 5ae58352cbee1251a0140879f04fc7c304cae674..89a5feb6308bcac537562c3dc4e61c16c92e460c 100644
> > > > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > > > @@ -824,8 +824,12 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
> > > > > >         struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state);
> > > > > >         struct dpu_sw_pipe_cfg *pipe_cfg;
> > > > > >         struct dpu_sw_pipe_cfg *r_pipe_cfg;
> > > > > > +       struct dpu_sw_pipe_cfg init_pipe_cfg;
> > > > > >         struct drm_rect fb_rect = { 0 };
> > > > > > +       const struct drm_display_mode *mode = &crtc_state->adjusted_mode;
> > > > > >         uint32_t max_linewidth;
> > > > > > +       u32 num_lm;
> > > > > > +       int stage_id, num_stages;
> > > > > >
> > > > > >         min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
> > > > > >         max_scale = MAX_DOWNSCALE_RATIO << 16;
> > > > > > @@ -848,13 +852,10 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
> > > > > >                 return -EINVAL;
> > > > > >         }
> > > > > >
> > > > > > -       /* move the assignment here, to ease handling to another pairs later */
> > > > > > -       pipe_cfg = &pstate->pipe_cfg[0];
> > > > > > -       r_pipe_cfg = &pstate->pipe_cfg[1];
> > > > > > -       /* state->src is 16.16, src_rect is not */
> > > > > > -       drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src);
> > > > > > +       num_lm = dpu_crtc_get_num_lm(crtc_state);
> > > > > >
> > > > > > -       pipe_cfg->dst_rect = new_plane_state->dst;
> > > > > > +       /* state->src is 16.16, src_rect is not */
> > > > > > +       drm_rect_fp_to_int(&init_pipe_cfg.src_rect, &new_plane_state->src);
> > > > > >
> > > > > >         fb_rect.x2 = new_plane_state->fb->width;
> > > > > >         fb_rect.y2 = new_plane_state->fb->height;
> > > > > > @@ -879,35 +880,94 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
> > > > > >
> > > > > >         max_linewidth = pdpu->catalog->caps->max_linewidth;
> > > > > >
> > > > > > -       drm_rect_rotate(&pipe_cfg->src_rect,
> > > > > > +       drm_rect_rotate(&init_pipe_cfg.src_rect,
> > > > > >                         new_plane_state->fb->width, new_plane_state->fb->height,
> > > > > >                         new_plane_state->rotation);
> > > > > >
> > > > > > -       if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) ||
> > > > > > -            _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) {
> > > > > > -               if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) {
> > > > > > -                       DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n",
> > > > > > -                                       DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);
> > > > > > -                       return -E2BIG;
> > > > > > +       /*
> > > > > > +        * We have 1 mixer pair cfg for 1:1:1 and 2:2:1 topology, 2 mixer pair
> > > > > > +        * configs for left and right half screen in case of 4:4:2 topology.
> > > > > > +        * But we may have 2 rect to split wide plane that exceeds limit with 1
> > > > > > +        * config for 2:2:1. So need to handle both wide plane splitting, and
> > > > > > +        * two halves of screen splitting for quad-pipe case. Check dest
> > > > > > +        * rectangle left/right clipping first, then check wide rectangle
> > > > > > +        * splitting in every half next.
> > > > > > +        */
> > > > > > +       num_stages = (num_lm + 1) / 2;
> > > > >
> > > > > Hi Dmitry,
> > > > > Because the plane is checked before crtc is checked in the drm framework. While
> > > > > the topology is decided in crtc check. Thus num_lm is 0 when this function is
> > > > > called for the first time. As a result, the below iteration is not run
> > > > > at all and leads
> > > > >  to iommu warning.
> > > >
> > > > How does it lead to IOMMU warnings?
> > >
> > > Because the pipe is not configured with width/height etc when the iteration is
> > > skipped. I have not found the root cause so far. But per the null IOMMU iova
> > > value, suppose it is due to DMA buffer not being prepared when DMA is started.
> >
> > I'd think, that corresponding SRC regs are either garbage or zero programmed.
>
> You are right in that. Sorry for my words is not accurate. I mean the
> DMA buffer is not
> feed to DMA engine correctly.
> >
> > >
> > > >
> > > > > Do you suggest to change drm framework with adding extra crtc check before
> > > > > plane check, or you prefer the below line here?
> > > > >
> > > > > num_stages = max(1, (num_lm + 1) / 2);
> > > >
> > > > DRM framework provides enough hooks to be able to influence the order or
> > > > operations without changing the framework. But, I'd like to point out
> > > > that for the virtual plane case we already perform plane operations
> > > > from dpu_crtc_atomic_check(). You can employ the same approach.
> > >
> > > Thanks for the suggestion! I see dpu_assign_plane_resources() is called
> > > from crtc side, which avoids the plane splitting before topology decision.
> > > To use this method, it looks like we are enabling the virtual plane by default.
> > > Because the virtual plane differs from the traditional method only with the
> > > plane splitting and resource preparation. Can we just enable the virtual
> > > plane by default in this situation?
> >
> > In which situation? It is a global switch. And we need to be able to
> > work with it turned off, until corresponding code is dropped.
>
> I mean the situation that the plane SSPP allocation and related resource
> preparation shall be deferred until crtc calling the plane API. In this way,
> the traditional plane management is almost identical with the virtual
> plane method. Or could you point out what shall differ for the two methods
> after we deferred the preparation? Thanks!

You just want to have different SSPP number limit for the 2 methods?
>
> Jun
> >
> > >
> > > Jun
> > >
> > > >
> > > >
> > > > --
> > > > With best wishes
> > > > Dmitry
> >
> > --
> > With best wishes
> > Dmitry

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v16 09/10] drm/msm/dpu: support plane splitting in quad-pipe case
  2026-01-15 10:10             ` Jun Nie
@ 2026-01-15 18:36               ` Dmitry Baryshkov
  0 siblings, 0 replies; 28+ messages in thread
From: Dmitry Baryshkov @ 2026-01-15 18:36 UTC (permalink / raw)
  To: Jun Nie
  Cc: Abhinav Kumar, Dmitry Baryshkov, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Rob Clark, linux-arm-msm, dri-devel,
	freedreno, linux-kernel

On Thu, Jan 15, 2026 at 06:10:36PM +0800, Jun Nie wrote:
> Jun Nie <jun.nie@linaro.org> 于2026年1月15日周四 17:57写道:
> >
> > Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> 于2026年1月15日周四 17:39写道:
> > >
> > > On Thu, Jan 15, 2026 at 05:34:28PM +0800, Jun Nie wrote:
> > > > Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> 于2026年1月15日周四 00:12写道:
> > > > >
> > > > > On Wed, Jan 14, 2026 at 10:48:17PM +0800, Jun Nie wrote:
> > > > > > Jun Nie <jun.nie@linaro.org> 于2025年9月18日周四 21:30写道:
> > > > > > >
> > > > > > > The content of every half of screen is sent out via one interface in
> > > > > > > dual-DSI case. The content for every interface is blended by a LM
> > > > > > > pair in quad-pipe case, thus a LM pair should not blend any content
> > > > > > > that cross the half of screen in this case. Clip plane into pipes per
> > > > > > > left and right half screen ROI if topology is quad pipe case.
> > > > > > >
> > > > > > > The clipped rectangle on every half of screen is futher handled by two
> > > > > > > pipes if its width exceeds a limit for a single pipe.
> > > > > > >
> > > > > > > Signed-off-by: Jun Nie <jun.nie@linaro.org>
> > > > > > > Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > > > > Reviewed-by: Jessica Zhang <jessica.zhang@oss.qualcomm.com>
> > > > > > > ---
> > > > > > >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c  |  11 +++
> > > > > > >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h  |   2 +
> > > > > > >  drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 137 +++++++++++++++++++++---------
> > > > > > >  3 files changed, 110 insertions(+), 40 deletions(-)
> > > > > > >
> > > > > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > > > > index d825eb8e40ae8bd456ede6269951339e3053d0d3..e925d93b38feac0594d735fdc2c5b9fd5ae83e6a 100644
> > > > > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > > > > @@ -1604,6 +1604,17 @@ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en)
> > > > > > >         return 0;
> > > > > > >  }
> > > > > > >
> > > > > > > +/**
> > > > > > > + * dpu_crtc_get_num_lm - Get mixer number in this CRTC pipeline
> > > > > > > + * @state: Pointer to drm crtc state object
> > > > > > > + */
> > > > > > > +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state)
> > > > > > > +{
> > > > > > > +       struct dpu_crtc_state *cstate = to_dpu_crtc_state(state);
> > > > > > > +
> > > > > > > +       return cstate->num_mixers;
> > > > > > > +}
> > > > > > > +
> > > > > > >  #ifdef CONFIG_DEBUG_FS
> > > > > > >  static int _dpu_debugfs_status_show(struct seq_file *s, void *data)
> > > > > > >  {
> > > > > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > > > > > > index 94392b9b924546f96e738ae20920cf9afd568e6b..6eaba5696e8e6bd1246a9895c4c8714ca6589b10 100644
> > > > > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > > > > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > > > > > > @@ -267,4 +267,6 @@ static inline enum dpu_crtc_client_type dpu_crtc_get_client_type(
> > > > > > >
> > > > > > >  void dpu_crtc_frame_event_cb(struct drm_crtc *crtc, u32 event);
> > > > > > >
> > > > > > > +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state);
> > > > > > > +
> > > > > > >  #endif /* _DPU_CRTC_H_ */
> > > > > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > > > > index 5ae58352cbee1251a0140879f04fc7c304cae674..89a5feb6308bcac537562c3dc4e61c16c92e460c 100644
> > > > > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > > > > @@ -824,8 +824,12 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
> > > > > > >         struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state);
> > > > > > >         struct dpu_sw_pipe_cfg *pipe_cfg;
> > > > > > >         struct dpu_sw_pipe_cfg *r_pipe_cfg;
> > > > > > > +       struct dpu_sw_pipe_cfg init_pipe_cfg;
> > > > > > >         struct drm_rect fb_rect = { 0 };
> > > > > > > +       const struct drm_display_mode *mode = &crtc_state->adjusted_mode;
> > > > > > >         uint32_t max_linewidth;
> > > > > > > +       u32 num_lm;
> > > > > > > +       int stage_id, num_stages;
> > > > > > >
> > > > > > >         min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
> > > > > > >         max_scale = MAX_DOWNSCALE_RATIO << 16;
> > > > > > > @@ -848,13 +852,10 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
> > > > > > >                 return -EINVAL;
> > > > > > >         }
> > > > > > >
> > > > > > > -       /* move the assignment here, to ease handling to another pairs later */
> > > > > > > -       pipe_cfg = &pstate->pipe_cfg[0];
> > > > > > > -       r_pipe_cfg = &pstate->pipe_cfg[1];
> > > > > > > -       /* state->src is 16.16, src_rect is not */
> > > > > > > -       drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src);
> > > > > > > +       num_lm = dpu_crtc_get_num_lm(crtc_state);
> > > > > > >
> > > > > > > -       pipe_cfg->dst_rect = new_plane_state->dst;
> > > > > > > +       /* state->src is 16.16, src_rect is not */
> > > > > > > +       drm_rect_fp_to_int(&init_pipe_cfg.src_rect, &new_plane_state->src);
> > > > > > >
> > > > > > >         fb_rect.x2 = new_plane_state->fb->width;
> > > > > > >         fb_rect.y2 = new_plane_state->fb->height;
> > > > > > > @@ -879,35 +880,94 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
> > > > > > >
> > > > > > >         max_linewidth = pdpu->catalog->caps->max_linewidth;
> > > > > > >
> > > > > > > -       drm_rect_rotate(&pipe_cfg->src_rect,
> > > > > > > +       drm_rect_rotate(&init_pipe_cfg.src_rect,
> > > > > > >                         new_plane_state->fb->width, new_plane_state->fb->height,
> > > > > > >                         new_plane_state->rotation);
> > > > > > >
> > > > > > > -       if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) ||
> > > > > > > -            _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) {
> > > > > > > -               if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) {
> > > > > > > -                       DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n",
> > > > > > > -                                       DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);
> > > > > > > -                       return -E2BIG;
> > > > > > > +       /*
> > > > > > > +        * We have 1 mixer pair cfg for 1:1:1 and 2:2:1 topology, 2 mixer pair
> > > > > > > +        * configs for left and right half screen in case of 4:4:2 topology.
> > > > > > > +        * But we may have 2 rect to split wide plane that exceeds limit with 1
> > > > > > > +        * config for 2:2:1. So need to handle both wide plane splitting, and
> > > > > > > +        * two halves of screen splitting for quad-pipe case. Check dest
> > > > > > > +        * rectangle left/right clipping first, then check wide rectangle
> > > > > > > +        * splitting in every half next.
> > > > > > > +        */
> > > > > > > +       num_stages = (num_lm + 1) / 2;
> > > > > >
> > > > > > Hi Dmitry,
> > > > > > Because the plane is checked before crtc is checked in the drm framework. While
> > > > > > the topology is decided in crtc check. Thus num_lm is 0 when this function is
> > > > > > called for the first time. As a result, the below iteration is not run
> > > > > > at all and leads
> > > > > >  to iommu warning.
> > > > >
> > > > > How does it lead to IOMMU warnings?
> > > >
> > > > Because the pipe is not configured with width/height etc when the iteration is
> > > > skipped. I have not found the root cause so far. But per the null IOMMU iova
> > > > value, suppose it is due to DMA buffer not being prepared when DMA is started.
> > >
> > > I'd think, that corresponding SRC regs are either garbage or zero programmed.
> >
> > You are right in that. Sorry for my words is not accurate. I mean the
> > DMA buffer is not
> > feed to DMA engine correctly.
> > >
> > > >
> > > > >
> > > > > > Do you suggest to change drm framework with adding extra crtc check before
> > > > > > plane check, or you prefer the below line here?
> > > > > >
> > > > > > num_stages = max(1, (num_lm + 1) / 2);
> > > > >
> > > > > DRM framework provides enough hooks to be able to influence the order or
> > > > > operations without changing the framework. But, I'd like to point out
> > > > > that for the virtual plane case we already perform plane operations
> > > > > from dpu_crtc_atomic_check(). You can employ the same approach.
> > > >
> > > > Thanks for the suggestion! I see dpu_assign_plane_resources() is called
> > > > from crtc side, which avoids the plane splitting before topology decision.
> > > > To use this method, it looks like we are enabling the virtual plane by default.
> > > > Because the virtual plane differs from the traditional method only with the
> > > > plane splitting and resource preparation. Can we just enable the virtual
> > > > plane by default in this situation?
> > >
> > > In which situation? It is a global switch. And we need to be able to
> > > work with it turned off, until corresponding code is dropped.
> >
> > I mean the situation that the plane SSPP allocation and related resource
> > preparation shall be deferred until crtc calling the plane API. In this way,
> > the traditional plane management is almost identical with the virtual
> > plane method. Or could you point out what shall differ for the two methods
> > after we deferred the preparation? Thanks!
> 
> You just want to have different SSPP number limit for the 2 methods?

I'm not sure I foolow. Two methods provide different ways of handling
plane <-> SSPP relationship. In non-virtual planes, you'd still have a
fixed pipe <-> plane. I wanted to point out the way to push some of the
checks to the atomic_check(crtc) time. Bonus point if that's unified
between virtual and non-virtual paths.


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2026-01-15 18:36 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-18 13:28 [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface Jun Nie
2025-09-18 13:28 ` [PATCH v16 01/10] drm/msm/dpu: fix mixer number counter on allocation Jun Nie
2025-09-18 13:28 ` [PATCH v16 02/10] drm/msm/dpu: bind correct pingpong for quad pipe Jun Nie
2025-09-18 13:28 ` [PATCH v16 03/10] drm/msm/dpu: Add pipe as trace argument Jun Nie
2025-09-18 13:28 ` [PATCH v16 04/10] drm/msm/dpu: handle pipes as array Jun Nie
2025-09-18 13:28 ` [PATCH v16 05/10] drm/msm/dpu: split PIPES_PER_STAGE definition per plane and mixer Jun Nie
2025-09-18 13:28 ` [PATCH v16 06/10] drm/msm/dpu: Use dedicated WB number definition Jun Nie
2025-09-18 13:28 ` [PATCH v16 07/10] drm/msm/dpu: blend pipes per mixer pairs config Jun Nie
2025-09-18 13:29 ` [PATCH v16 08/10] drm/msm/dpu: support SSPP assignment for quad-pipe case Jun Nie
2025-09-18 13:29 ` [PATCH v16 09/10] drm/msm/dpu: support plane splitting in " Jun Nie
2025-12-18 12:44   ` Abel Vesa
2026-01-14 14:48   ` Jun Nie
2026-01-14 16:12     ` Dmitry Baryshkov
2026-01-15  9:34       ` Jun Nie
2026-01-15  9:38         ` Dmitry Baryshkov
2026-01-15  9:57           ` Jun Nie
2026-01-15 10:10             ` Jun Nie
2026-01-15 18:36               ` Dmitry Baryshkov
2025-09-18 13:29 ` [PATCH v16 10/10] drm/msm/dpu: Enable quad-pipe for DSC and dual-DSI case Jun Nie
2025-09-19 16:57   ` Dmitry Baryshkov
2025-11-29 16:37   ` Marijn Suijten
2025-12-02  4:18     ` Jun Nie
2025-12-10 19:30     ` Dmitry Baryshkov
2025-12-11 15:53       ` Jun Nie
2025-12-18 22:04         ` Marijn Suijten
2025-09-19  0:41 ` [PATCH v16 00/10] drm/msm/dpu: Support quad pipe with dual-interface Dmitry Baryshkov
2025-09-19 18:50   ` Dmitry Baryshkov
2025-11-14 14:26 ` Dmitry Baryshkov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox