mbox series

[v4,00/30] drm/msm/dpu: wide planes support

Message ID 20230303125725.3695011-1-dmitry.baryshkov@linaro.org
Headers show
Series drm/msm/dpu: wide planes support | expand

Message

Dmitry Baryshkov March 3, 2023, 12:56 p.m. UTC
This patchset brings in multirect usage to support using two SSPP
rectangles for a single plane. Full virtual planes support is omitted
from this pull request, it will come later.

Changes since v3:

- moved if (!pipe->sspp) checks back to the calling site, the caller
  should know if there is a backing SSPP or not.
- Restored state_idx argument of trace_dpu_crtc_setup_mixer trace point
- Removed .smart_dma_rev from dpu_caps
- Added cleaning of multirect to _dpu_plane_atomic_disable()
- Per Abhinavs request split the SmartDMA enablement patch into the
  "verified by me" and "the rest of the platforms" patches, which is not
  supposed to be merged in. Users of other platforms are supposed to
  verify multirect support on their platforms and then send patches
  enabling SmartDMA for their SoC.
- Expanded several commit messages

Changes since v2:

- Renamed dpu_hw_pipe_cfg to dpu_hw_sspp_cfg
- Added a patch to clean up src add / layout for the solid fill planes
- Fixed several comments and commit messages which caused confusion
- Added documentation for new dpu_plane_state members
- Slightly reworked dpu_plane_atomic_check() to make it more logical and obvious.

Changes since v1 (which was ages ago):
- Rebased on top of 6.2-rc1
- Dropped the controversial _dpu_crtc_blend_setup() split patch
- Renamed dpu_hw_pipe to dpu_hw_sspp
- Other misc changes

Dmitry Baryshkov (30):
  drm/msm/dpu: rename struct dpu_hw_pipe(_cfg) to dpu_hw_sspp(_cfg)
  drm/msm/dpu: move SSPP allocation to the RM
  drm/msm/dpu: move SSPP debugfs creation to dpu_kms.c
  drm/msm/dpu: drop EAGAIN check from dpu_format_populate_layout
  drm/msm/dpu: move pipe_hw to dpu_plane_state
  drm/msm/dpu: drop dpu_plane_pipe function
  drm/msm/dpu: introduce struct dpu_sw_pipe
  drm/msm/dpu: use dpu_sw_pipe for dpu_hw_sspp callbacks
  drm/msm/dpu: pass dpu_format to _dpu_hw_sspp_setup_scaler3()
  drm/msm/dpu: clean up SRC addresses when setting up SSPP for solid
    fill
  drm/msm/dpu: move stride programming to
    dpu_hw_sspp_setup_sourceaddress
  drm/msm/dpu: remove dpu_hw_fmt_layout from struct dpu_hw_sspp_cfg
  drm/msm/dpu: rename dpu_hw_sspp_cfg to dpu_sw_pipe_cfg
  drm/msm/dpu: drop src_split and multirect check from
    dpu_crtc_atomic_check
  drm/msm/dpu: don't use unsupported blend stages
  drm/msm/dpu: move the rest of plane checks to dpu_plane_atomic_check()
  drm/msm/dpu: drop redundant plane dst check from
    dpu_crtc_atomic_check()
  drm/msm/dpu: rewrite plane's QoS-related functions to take dpu_sw_pipe
    and dpu_format
  drm/msm/dpu: make _dpu_plane_calc_clk accept mode directly
  drm/msm/dpu: add dpu_hw_sspp_cfg to dpu_plane_state
  drm/msm/dpu: simplify dpu_plane_validate_src()
  drm/msm/dpu: rework dpu_plane_sspp_atomic_update()
  drm/msm/dpu: rework dpu_plane_atomic_check()
  drm/msm/dpu: rework plane CSC setting
  drm/msm/dpu: rework static color fill code
  drm/msm/dpu: split pipe handling from _dpu_crtc_blend_setup_mixer
  drm/msm/dpu: add support for wide planes
  drm/msm/dpu: populate SmartDMA features in hw catalog
  drm/msm/dpu: enable SmartDMA for the rest of the platforms
  drm/msm/dpu: drop smart_dma_rev from dpu_caps

 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c      | 289 ++-----
 drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c   |  10 +-
 .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c    |  23 +-
 .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h    |   2 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c   | 169 ++--
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h   | 111 ++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c       |  18 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c     | 756 ++++++++++--------
 drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h     |  23 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c        |  22 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h        |  12 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h     |  19 +-
 12 files changed, 719 insertions(+), 735 deletions(-)

Comments

Abhinav Kumar March 8, 2023, 11:14 p.m. UTC | #1
On 3/3/2023 4:57 AM, Dmitry Baryshkov wrote:
> Typically SSPP can support rectangle with width up to 2560. However it's
> possible to use multirect feature and split source to use the SSPP to
> output two consecutive rectangles. This commit brings in this capability
> to support wider screen resolutions.
> 
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
>   drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c  |  19 +++-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 125 +++++++++++++++++++---
>   drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h |   4 +
>   3 files changed, 133 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> index e651e4593280..03034ec8ed1b 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> @@ -480,6 +480,15 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
>   					   format, fb ? fb->modifier : 0,
>   					   &pstate->pipe, 0, stage_cfg);
>   
> +		if (pstate->r_pipe.sspp) {
> +			set_bit(pstate->r_pipe.sspp->idx, fetch_active);
> +			_dpu_crtc_blend_setup_pipe(crtc, plane,
> +						   mixer, cstate->num_mixers,
> +						   pstate->stage,
> +						   format, fb ? fb->modifier : 0,
> +						   &pstate->pipe, 1, stage_cfg);
> +		}
> +
>   		/* blend config update */
>   		for (lm_idx = 0; lm_idx < cstate->num_mixers; lm_idx++) {
>   			_dpu_crtc_setup_blend_cfg(mixer + lm_idx, pstate, format);
> @@ -1316,10 +1325,16 @@ 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:%s\n",
> +		seq_printf(s, "\tsspp[0]:%s\n",
>   			   pstate->pipe.sspp->cap->name);
> -		seq_printf(s, "\tmultirect: mode: %d index: %d\n",
> +		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);
> +		}
>   
>   		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 3d798b939faa..06fbe5ef7ff2 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> @@ -701,6 +701,10 @@ static void _dpu_plane_color_fill(struct dpu_plane *pdpu,
>   	/* 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,
> +					   fill_color, fmt);
>   }
>   
>   int dpu_plane_validate_multirect_v2(struct dpu_multirect_plane_states *plane)
> @@ -958,9 +962,12 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
>   	int ret = 0, min_scale;
>   	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;
>   	const struct drm_crtc_state *crtc_state = NULL;
>   	const struct dpu_format *fmt;
>   	struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg;
> +	struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg;
>   	struct drm_rect fb_rect = { 0 };
>   	uint32_t max_linewidth;
>   	unsigned int rotation;
> @@ -984,8 +991,11 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
>   	if (!new_plane_state->visible)
>   		return 0;
>   
> -	pstate->pipe.multirect_index = DPU_SSPP_RECT_SOLO;
> -	pstate->pipe.multirect_mode = DPU_SSPP_MULTIRECT_NONE;
> +	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;
> +	r_pipe->sspp = NULL;
>   
>   	pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos;
>   	if (pstate->stage >= pdpu->catalog->caps->max_mixer_blendstages) {
> @@ -1017,19 +1027,58 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
>   
>   	max_linewidth = pdpu->catalog->caps->max_linewidth;
>   
> -	/* check decimated source width */
>   	if (drm_rect_width(&pipe_cfg->src_rect) > 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;
> +		/* struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc_state); */
> +
> +		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;
> +		}
> +
> +		/*
> +		 * FIXME: it's not possible to check if sourcesplit is supported,
> +		 * LMs is not assigned yet. It happens in dpu_encoder_virt_mode_set
> +		 */
> +		if (drm_rect_width(&pipe_cfg->src_rect) != drm_rect_width(&pipe_cfg->dst_rect) ||
> +			   drm_rect_height(&pipe_cfg->src_rect) != drm_rect_height(&pipe_cfg->dst_rect) ||
> +			   (!test_bit(DPU_SSPP_SMART_DMA_V1, &pipe->sspp->cap->features) &&
> +			    !test_bit(DPU_SSPP_SMART_DMA_V2, &pipe->sspp->cap->features)) ||
> +			   /* cstate->num_mixers < 2 ||
> +			   !test_bit(DPU_MIXER_SOURCESPLIT, &cstate->mixers[0].hw_lm->cap->features) || */
> +			   DPU_FORMAT_IS_YUV(fmt)) {
> +			DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u, can't use split source\n",
> +					DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);
> +			return -E2BIG;
> +		}
This patch throws a compilation warning (which seems correct) which 
fails on my CrOS tree

/mnt/host/source/src/third_party/kernel/v5.15/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c:1049:25: 
error: variable 'fmt' is uninitialized when used here 
[-Werror,-Wuninitialized]
                            DPU_FORMAT_IS_YUV(fmt)) {
                                              ^~~
/mnt/host/source/src/third_party/kernel/v5.15/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h:49:38: 
note: expanded from macro 'DPU_FORMAT_IS_YUV'
         (test_bit(DPU_FORMAT_FLAG_YUV_BIT, (X)->flag))
                                             ^
/mnt/host/source/src/third_party/kernel/v5.15/include/linux/bitops.h:61:50: 
note: expanded from macro 'test_bit'
#define test_bit(nr, addr)              bitop(_test_bit, nr, addr)
                                                              ^~~~
/mnt/host/source/src/third_party/kernel/v5.15/include/linux/bitops.h:50:37: 
note: expanded from macro 'bitop'
           __builtin_constant_p((uintptr_t)(addr) != (uintptr_t)NULL) && \

I have fixed this by making this change:

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index 06fbe5ef7ff2..9a03d1cad0ee 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -1027,6 +1027,8 @@ static int dpu_plane_atomic_check(struct drm_plane 
*plane,

         max_linewidth = pdpu->catalog->caps->max_linewidth;

+       fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
+
         if (drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) {
                 /* struct dpu_crtc_state *cstate = 
to_dpu_crtc_state(crtc_state); */

@@ -1067,8 +1069,6 @@ static int dpu_plane_atomic_check(struct drm_plane 
*plane,
                 r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2;
         }

-       fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
-
         ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt);
         if (ret)
                 return ret;

Perhaps you can absorb this into your patch.

But this makes me wonder, no YUV cases were tested with this series so far?

> +
> +		/* Use multirect for wide plane. We do not support dynamic assignment of SSPPs, so we know the configuration. */
> +		pipe->multirect_index = DPU_SSPP_RECT_0;
> +		pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
> +
> +		r_pipe->sspp = pipe->sspp;
> +		r_pipe->multirect_index = DPU_SSPP_RECT_1;
> +		r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
> +
> +		*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;
>   	}
>   
>   	fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
>   
> -	ret = dpu_plane_atomic_check_pipe(pdpu, &pstate->pipe, pipe_cfg, fmt);
> +	ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt);
>   	if (ret)
>   		return ret;
>   
> +	if (r_pipe->sspp) {
> +		ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, fmt);
> +		if (ret)
> +			return ret;
> +	}
> +
>   	supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0;
>   
>   	if (pipe_hw_caps->features & BIT(DPU_SSPP_INLINE_ROTATION))
> @@ -1096,8 +1145,10 @@ void dpu_plane_flush(struct drm_plane *plane)
>   	else if (pdpu->color_fill & DPU_PLANE_COLOR_FILL_FLAG)
>   		/* force 100% alpha */
>   		_dpu_plane_color_fill(pdpu, pdpu->color_fill, 0xFF);
> -	else
> +	else {
>   		dpu_plane_flush_csc(pdpu, &pstate->pipe);
> +		dpu_plane_flush_csc(pdpu, &pstate->r_pipe);
> +	}
>   
>   	/* flag h/w flush complete */
>   	if (plane->state)
> @@ -1209,13 +1260,14 @@ static void dpu_plane_sspp_atomic_update(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 *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 dpu_format *fmt =
>   		to_dpu_format(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;
>   	struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);
>   	struct msm_gem_address_space *aspace = kms->base.aspace;
>   	struct dpu_hw_fmt_layout layout;
> @@ -1243,6 +1295,12 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane)
>   				   drm_mode_vrefresh(&crtc->mode),
>   				   layout_valid ? &layout : NULL);
>   
> +	if (r_pipe->sspp) {
> +		dpu_plane_sspp_update_pipe(plane, r_pipe, r_pipe_cfg, fmt,
> +					   drm_mode_vrefresh(&crtc->mode),
> +					   layout_valid ? &layout : NULL);
> +	}
> +
>   	if (pstate->needs_qos_remap)
>   		pstate->needs_qos_remap = false;
>   
> @@ -1250,16 +1308,31 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane)
>   						    &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_clk = max(pstate->plane_clk, _dpu_plane_calc_clk(&crtc->mode, r_pipe_cfg));
> +	}
>   }
>   
>   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;
>   
>   	trace_dpu_plane_disable(DRMID(plane), false,
>   				pstate->pipe.multirect_mode);
>   
> +	if (r_pipe->sspp) {
> +		r_pipe->multirect_index = DPU_SSPP_RECT_SOLO;
> +		r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
> +
> +		if (r_pipe->sspp->ops.setup_multirect)
> +			r_pipe->sspp->ops.setup_multirect(r_pipe);
> +	}
> +
>   	pstate->pending = true;
>   }
>   
> @@ -1292,6 +1365,9 @@ static void dpu_plane_destroy(struct drm_plane *plane)
>   		pstate = to_dpu_plane_state(plane->state);
>   		_dpu_plane_set_qos_ctrl(plane, &pstate->pipe, false, DPU_PLANE_QOS_PANIC_CTRL);
>   
> +		if (pstate->r_pipe.sspp)
> +			_dpu_plane_set_qos_ctrl(plane, &pstate->r_pipe, false, DPU_PLANE_QOS_PANIC_CTRL);
> +
>   		mutex_destroy(&pdpu->lock);
>   
>   		/* this will destroy the states as well */
> @@ -1372,12 +1448,29 @@ 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;
>   
>   	drm_printf(p, "\tstage=%d\n", pstate->stage);
> -	drm_printf(p, "\tsspp=%s\n", pstate->pipe.sspp->cap->name);
> -	drm_printf(p, "\tmultirect_mode=%s\n", dpu_get_multirect_mode(pstate->pipe.multirect_mode));
> -	drm_printf(p, "\tmultirect_index=%s\n",
> -		   dpu_get_multirect_index(pstate->pipe.multirect_index));
> +
> +	drm_printf(p, "\tsspp[0]=%s\n", pipe->sspp->cap->name);
> +	drm_printf(p, "\tmultirect_mode[0]=%s\n", dpu_get_multirect_mode(pipe->multirect_mode));
> +	drm_printf(p, "\tmultirect_index[0]=%s\n",
> +		   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));
> +	}
>   }
>   
>   static void dpu_plane_reset(struct drm_plane *plane)
> @@ -1411,6 +1504,10 @@ static void dpu_plane_reset(struct drm_plane *plane)
>   	 * This is the place where the state is allocated, so fill it fully.
>   	 */
>   	pstate->pipe.sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
> +	pstate->pipe.multirect_index = DPU_SSPP_RECT_SOLO;
> +	pstate->pipe.multirect_mode = DPU_SSPP_MULTIRECT_NONE;
> +
> +	pstate->r_pipe.sspp = NULL;
>   
>   	__drm_atomic_helper_plane_reset(plane, &pstate->base);
>   }
> @@ -1427,6 +1524,8 @@ void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable)
>   
>   	pm_runtime_get_sync(&dpu_kms->pdev->dev);
>   	_dpu_plane_set_qos_ctrl(plane, &pstate->pipe, enable, DPU_PLANE_QOS_PANIC_CTRL);
> +	if (pstate->r_pipe.sspp)
> +		_dpu_plane_set_qos_ctrl(plane, &pstate->r_pipe, enable, DPU_PLANE_QOS_PANIC_CTRL);
>   	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 0ca9002015ff..7490ffd94d03 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> @@ -19,7 +19,9 @@
>    * @base:	base drm plane state object
>    * @aspace:	pointer to address space for input/output buffers
>    * @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
>    * @stage:	assigned by crtc blender
>    * @needs_qos_remap: qos remap settings need to be updated
>    * @multirect_index: index of the rectangle of SSPP
> @@ -34,7 +36,9 @@ struct dpu_plane_state {
>   	struct drm_plane_state base;
>   	struct msm_gem_address_space *aspace;
>   	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;
>   	enum dpu_stage stage;
>   	bool needs_qos_remap;
>   	bool pending;
Dmitry Baryshkov March 9, 2023, 9:01 a.m. UTC | #2
On 09/03/2023 01:14, Abhinav Kumar wrote:
> 
> 
> On 3/3/2023 4:57 AM, Dmitry Baryshkov wrote:
>> Typically SSPP can support rectangle with width up to 2560. However it's
>> possible to use multirect feature and split source to use the SSPP to
>> output two consecutive rectangles. This commit brings in this capability
>> to support wider screen resolutions.
>>
>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>> ---
>>   drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c  |  19 +++-
>>   drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 125 +++++++++++++++++++---
>>   drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h |   4 +
>>   3 files changed, 133 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
>> b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>> index e651e4593280..03034ec8ed1b 100644
>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>> @@ -480,6 +480,15 @@ static void _dpu_crtc_blend_setup_mixer(struct 
>> drm_crtc *crtc,
>>                          format, fb ? fb->modifier : 0,
>>                          &pstate->pipe, 0, stage_cfg);
>> +        if (pstate->r_pipe.sspp) {
>> +            set_bit(pstate->r_pipe.sspp->idx, fetch_active);
>> +            _dpu_crtc_blend_setup_pipe(crtc, plane,
>> +                           mixer, cstate->num_mixers,
>> +                           pstate->stage,
>> +                           format, fb ? fb->modifier : 0,
>> +                           &pstate->pipe, 1, stage_cfg);
>> +        }
>> +
>>           /* blend config update */
>>           for (lm_idx = 0; lm_idx < cstate->num_mixers; lm_idx++) {
>>               _dpu_crtc_setup_blend_cfg(mixer + lm_idx, pstate, format);
>> @@ -1316,10 +1325,16 @@ 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:%s\n",
>> +        seq_printf(s, "\tsspp[0]:%s\n",
>>                  pstate->pipe.sspp->cap->name);
>> -        seq_printf(s, "\tmultirect: mode: %d index: %d\n",
>> +        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);
>> +        }
>>           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 3d798b939faa..06fbe5ef7ff2 100644
>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>> @@ -701,6 +701,10 @@ static void _dpu_plane_color_fill(struct 
>> dpu_plane *pdpu,
>>       /* 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,
>> +                       fill_color, fmt);
>>   }
>>   int dpu_plane_validate_multirect_v2(struct 
>> dpu_multirect_plane_states *plane)
>> @@ -958,9 +962,12 @@ static int dpu_plane_atomic_check(struct 
>> drm_plane *plane,
>>       int ret = 0, min_scale;
>>       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;
>>       const struct drm_crtc_state *crtc_state = NULL;
>>       const struct dpu_format *fmt;
>>       struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg;
>> +    struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg;
>>       struct drm_rect fb_rect = { 0 };
>>       uint32_t max_linewidth;
>>       unsigned int rotation;
>> @@ -984,8 +991,11 @@ static int dpu_plane_atomic_check(struct 
>> drm_plane *plane,
>>       if (!new_plane_state->visible)
>>           return 0;
>> -    pstate->pipe.multirect_index = DPU_SSPP_RECT_SOLO;
>> -    pstate->pipe.multirect_mode = DPU_SSPP_MULTIRECT_NONE;
>> +    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;
>> +    r_pipe->sspp = NULL;
>>       pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos;
>>       if (pstate->stage >= pdpu->catalog->caps->max_mixer_blendstages) {
>> @@ -1017,19 +1027,58 @@ static int dpu_plane_atomic_check(struct 
>> drm_plane *plane,
>>       max_linewidth = pdpu->catalog->caps->max_linewidth;
>> -    /* check decimated source width */
>>       if (drm_rect_width(&pipe_cfg->src_rect) > 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;
>> +        /* struct dpu_crtc_state *cstate = 
>> to_dpu_crtc_state(crtc_state); */
>> +
>> +        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;
>> +        }
>> +
>> +        /*
>> +         * FIXME: it's not possible to check if sourcesplit is 
>> supported,
>> +         * LMs is not assigned yet. It happens in 
>> dpu_encoder_virt_mode_set
>> +         */
>> +        if (drm_rect_width(&pipe_cfg->src_rect) != 
>> drm_rect_width(&pipe_cfg->dst_rect) ||
>> +               drm_rect_height(&pipe_cfg->src_rect) != 
>> drm_rect_height(&pipe_cfg->dst_rect) ||
>> +               (!test_bit(DPU_SSPP_SMART_DMA_V1, 
>> &pipe->sspp->cap->features) &&
>> +                !test_bit(DPU_SSPP_SMART_DMA_V2, 
>> &pipe->sspp->cap->features)) ||
>> +               /* cstate->num_mixers < 2 ||
>> +               !test_bit(DPU_MIXER_SOURCESPLIT, 
>> &cstate->mixers[0].hw_lm->cap->features) || */
>> +               DPU_FORMAT_IS_YUV(fmt)) {
>> +            DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " 
>> line:%u, can't use split source\n",
>> +                    DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);
>> +            return -E2BIG;
>> +        }
> This patch throws a compilation warning (which seems correct) which 
> fails on my CrOS tree

Thanks. Interesting enough I don't see this warning even with W=1.

> 
> /mnt/host/source/src/third_party/kernel/v5.15/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c:1049:25: error: variable 'fmt' is uninitialized when used here [-Werror,-Wuninitialized]
>                             DPU_FORMAT_IS_YUV(fmt)) {
>                                               ^~~
> /mnt/host/source/src/third_party/kernel/v5.15/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h:49:38: note: expanded from macro 'DPU_FORMAT_IS_YUV'
>          (test_bit(DPU_FORMAT_FLAG_YUV_BIT, (X)->flag))
>                                              ^
> /mnt/host/source/src/third_party/kernel/v5.15/include/linux/bitops.h:61:50: note: expanded from macro 'test_bit'
> #define test_bit(nr, addr)              bitop(_test_bit, nr, addr)
>                                                               ^~~~
> /mnt/host/source/src/third_party/kernel/v5.15/include/linux/bitops.h:50:37: note: expanded from macro 'bitop'
>            __builtin_constant_p((uintptr_t)(addr) != (uintptr_t)NULL) && \
> 
> I have fixed this by making this change:
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c 
> b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> index 06fbe5ef7ff2..9a03d1cad0ee 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> @@ -1027,6 +1027,8 @@ static int dpu_plane_atomic_check(struct drm_plane 
> *plane,
> 
>          max_linewidth = pdpu->catalog->caps->max_linewidth;
> 
> +       fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
> +
>          if (drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) {
>                  /* struct dpu_crtc_state *cstate = 
> to_dpu_crtc_state(crtc_state); */
> 
> @@ -1067,8 +1069,6 @@ static int dpu_plane_atomic_check(struct drm_plane 
> *plane,
>                  r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2;
>          }
> 
> -       fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
> -
>          ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt);
>          if (ret)
>                  return ret;
> 
> Perhaps you can absorb this into your patch.
> 
> But this makes me wonder, no YUV cases were tested with this series so far?

I tested it in the early days of the series, when it had the allocator, 
but I don't think I tested it recently.

> 
>> +
>> +        /* Use multirect for wide plane. We do not support dynamic 
>> assignment of SSPPs, so we know the configuration. */
>> +        pipe->multirect_index = DPU_SSPP_RECT_0;
>> +        pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
>> +
>> +        r_pipe->sspp = pipe->sspp;
>> +        r_pipe->multirect_index = DPU_SSPP_RECT_1;
>> +        r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
>> +
>> +        *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;
>>       }
>>       fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
>> -    ret = dpu_plane_atomic_check_pipe(pdpu, &pstate->pipe, pipe_cfg, 
>> fmt);
>> +    ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt);
>>       if (ret)
>>           return ret;
>> +    if (r_pipe->sspp) {
>> +        ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, 
>> fmt);
>> +        if (ret)
>> +            return ret;
>> +    }
>> +
>>       supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0;
>>       if (pipe_hw_caps->features & BIT(DPU_SSPP_INLINE_ROTATION))
>> @@ -1096,8 +1145,10 @@ void dpu_plane_flush(struct drm_plane *plane)
>>       else if (pdpu->color_fill & DPU_PLANE_COLOR_FILL_FLAG)
>>           /* force 100% alpha */
>>           _dpu_plane_color_fill(pdpu, pdpu->color_fill, 0xFF);
>> -    else
>> +    else {
>>           dpu_plane_flush_csc(pdpu, &pstate->pipe);
>> +        dpu_plane_flush_csc(pdpu, &pstate->r_pipe);
>> +    }
>>       /* flag h/w flush complete */
>>       if (plane->state)
>> @@ -1209,13 +1260,14 @@ static void 
>> dpu_plane_sspp_atomic_update(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 *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 dpu_format *fmt =
>>           to_dpu_format(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;
>>       struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);
>>       struct msm_gem_address_space *aspace = kms->base.aspace;
>>       struct dpu_hw_fmt_layout layout;
>> @@ -1243,6 +1295,12 @@ static void dpu_plane_sspp_atomic_update(struct 
>> drm_plane *plane)
>>                      drm_mode_vrefresh(&crtc->mode),
>>                      layout_valid ? &layout : NULL);
>> +    if (r_pipe->sspp) {
>> +        dpu_plane_sspp_update_pipe(plane, r_pipe, r_pipe_cfg, fmt,
>> +                       drm_mode_vrefresh(&crtc->mode),
>> +                       layout_valid ? &layout : NULL);
>> +    }
>> +
>>       if (pstate->needs_qos_remap)
>>           pstate->needs_qos_remap = false;
>> @@ -1250,16 +1308,31 @@ static void 
>> dpu_plane_sspp_atomic_update(struct drm_plane *plane)
>>                               &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_clk = max(pstate->plane_clk, 
>> _dpu_plane_calc_clk(&crtc->mode, r_pipe_cfg));
>> +    }
>>   }
>>   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;
>>       trace_dpu_plane_disable(DRMID(plane), false,
>>                   pstate->pipe.multirect_mode);
>> +    if (r_pipe->sspp) {
>> +        r_pipe->multirect_index = DPU_SSPP_RECT_SOLO;
>> +        r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
>> +
>> +        if (r_pipe->sspp->ops.setup_multirect)
>> +            r_pipe->sspp->ops.setup_multirect(r_pipe);
>> +    }
>> +
>>       pstate->pending = true;
>>   }
>> @@ -1292,6 +1365,9 @@ static void dpu_plane_destroy(struct drm_plane 
>> *plane)
>>           pstate = to_dpu_plane_state(plane->state);
>>           _dpu_plane_set_qos_ctrl(plane, &pstate->pipe, false, 
>> DPU_PLANE_QOS_PANIC_CTRL);
>> +        if (pstate->r_pipe.sspp)
>> +            _dpu_plane_set_qos_ctrl(plane, &pstate->r_pipe, false, 
>> DPU_PLANE_QOS_PANIC_CTRL);
>> +
>>           mutex_destroy(&pdpu->lock);
>>           /* this will destroy the states as well */
>> @@ -1372,12 +1448,29 @@ 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;
>>       drm_printf(p, "\tstage=%d\n", pstate->stage);
>> -    drm_printf(p, "\tsspp=%s\n", pstate->pipe.sspp->cap->name);
>> -    drm_printf(p, "\tmultirect_mode=%s\n", 
>> dpu_get_multirect_mode(pstate->pipe.multirect_mode));
>> -    drm_printf(p, "\tmultirect_index=%s\n",
>> -           dpu_get_multirect_index(pstate->pipe.multirect_index));
>> +
>> +    drm_printf(p, "\tsspp[0]=%s\n", pipe->sspp->cap->name);
>> +    drm_printf(p, "\tmultirect_mode[0]=%s\n", 
>> dpu_get_multirect_mode(pipe->multirect_mode));
>> +    drm_printf(p, "\tmultirect_index[0]=%s\n",
>> +           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));
>> +    }
>>   }
>>   static void dpu_plane_reset(struct drm_plane *plane)
>> @@ -1411,6 +1504,10 @@ static void dpu_plane_reset(struct drm_plane 
>> *plane)
>>        * This is the place where the state is allocated, so fill it 
>> fully.
>>        */
>>       pstate->pipe.sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
>> +    pstate->pipe.multirect_index = DPU_SSPP_RECT_SOLO;
>> +    pstate->pipe.multirect_mode = DPU_SSPP_MULTIRECT_NONE;
>> +
>> +    pstate->r_pipe.sspp = NULL;
>>       __drm_atomic_helper_plane_reset(plane, &pstate->base);
>>   }
>> @@ -1427,6 +1524,8 @@ void dpu_plane_danger_signal_ctrl(struct 
>> drm_plane *plane, bool enable)
>>       pm_runtime_get_sync(&dpu_kms->pdev->dev);
>>       _dpu_plane_set_qos_ctrl(plane, &pstate->pipe, enable, 
>> DPU_PLANE_QOS_PANIC_CTRL);
>> +    if (pstate->r_pipe.sspp)
>> +        _dpu_plane_set_qos_ctrl(plane, &pstate->r_pipe, enable, 
>> DPU_PLANE_QOS_PANIC_CTRL);
>>       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 0ca9002015ff..7490ffd94d03 100644
>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>> @@ -19,7 +19,9 @@
>>    * @base:    base drm plane state object
>>    * @aspace:    pointer to address space for input/output buffers
>>    * @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
>>    * @stage:    assigned by crtc blender
>>    * @needs_qos_remap: qos remap settings need to be updated
>>    * @multirect_index: index of the rectangle of SSPP
>> @@ -34,7 +36,9 @@ struct dpu_plane_state {
>>       struct drm_plane_state base;
>>       struct msm_gem_address_space *aspace;
>>       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;
>>       enum dpu_stage stage;
>>       bool needs_qos_remap;
>>       bool pending;