* [PATCH v4 01/13] drm/msm/dpu: take plane rotation into account for wide planes
2024-03-14 0:02 [PATCH v4 00/13] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
@ 2024-03-14 0:02 ` Dmitry Baryshkov
2024-05-30 22:51 ` Abhinav Kumar
2024-03-14 0:02 ` [PATCH v4 02/13] drm/msm/dpu: use drm_rect_fp_to_int() Dmitry Baryshkov
` (12 subsequent siblings)
13 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-03-14 0:02 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Abhinav Kumar, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
Take into account the plane rotation and flipping when calculating src
positions for the wide plane parts.
This is not an issue yet, because rotation is only supported for the
UBWC planes and wide UBWC planes are rejected anyway because in parallel
multirect case only the half of the usual width is supported for tiled
formats. However it's better to fix this now rather than stumbling upon
it later.
Fixes: 80e8ae3b38ab ("drm/msm/dpu: add support for wide planes")
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index ff975ad51145..44f35ae09ba6 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -862,6 +862,10 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
max_linewidth = pdpu->catalog->caps->max_linewidth;
+ drm_rect_rotate(&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) {
/*
@@ -911,6 +915,14 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2;
}
+ drm_rect_rotate_inv(&pipe_cfg->src_rect,
+ new_plane_state->fb->width, new_plane_state->fb->height,
+ new_plane_state->rotation);
+ if (r_pipe->sspp)
+ drm_rect_rotate_inv(&r_pipe_cfg->src_rect,
+ new_plane_state->fb->width, new_plane_state->fb->height,
+ new_plane_state->rotation);
+
ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt, &crtc_state->adjusted_mode);
if (ret)
return ret;
--
2.39.2
^ permalink raw reply related [flat|nested] 50+ messages in thread* Re: [PATCH v4 01/13] drm/msm/dpu: take plane rotation into account for wide planes
2024-03-14 0:02 ` [PATCH v4 01/13] drm/msm/dpu: take plane rotation into account for " Dmitry Baryshkov
@ 2024-05-30 22:51 ` Abhinav Kumar
0 siblings, 0 replies; 50+ messages in thread
From: Abhinav Kumar @ 2024-05-30 22:51 UTC (permalink / raw)
To: Dmitry Baryshkov, Rob Clark, Sean Paul, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> Take into account the plane rotation and flipping when calculating src
> positions for the wide plane parts.
>
> This is not an issue yet, because rotation is only supported for the
> UBWC planes and wide UBWC planes are rejected anyway because in parallel
> multirect case only the half of the usual width is supported for tiled
> formats. However it's better to fix this now rather than stumbling upon
> it later.
>
> Fixes: 80e8ae3b38ab ("drm/msm/dpu: add support for wide planes")
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v4 02/13] drm/msm/dpu: use drm_rect_fp_to_int()
2024-03-14 0:02 [PATCH v4 00/13] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
2024-03-14 0:02 ` [PATCH v4 01/13] drm/msm/dpu: take plane rotation into account for " Dmitry Baryshkov
@ 2024-03-14 0:02 ` Dmitry Baryshkov
2024-05-30 23:14 ` Abhinav Kumar
2024-03-14 0:02 ` [PATCH v4 03/13] drm/msm/dpu: move pstate->pipe initialization to dpu_plane_atomic_check Dmitry Baryshkov
` (11 subsequent siblings)
13 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-03-14 0:02 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Abhinav Kumar, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
Use the drm_rect_fp_to_int() helper instead of using the hand-written
code.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index 44f35ae09ba6..9c52fe3c0261 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -837,13 +837,8 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
return -EINVAL;
}
- pipe_cfg->src_rect = new_plane_state->src;
-
/* state->src is 16.16, src_rect is not */
- pipe_cfg->src_rect.x1 >>= 16;
- pipe_cfg->src_rect.x2 >>= 16;
- pipe_cfg->src_rect.y1 >>= 16;
- pipe_cfg->src_rect.y2 >>= 16;
+ drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src);
pipe_cfg->dst_rect = new_plane_state->dst;
--
2.39.2
^ permalink raw reply related [flat|nested] 50+ messages in thread* Re: [PATCH v4 02/13] drm/msm/dpu: use drm_rect_fp_to_int()
2024-03-14 0:02 ` [PATCH v4 02/13] drm/msm/dpu: use drm_rect_fp_to_int() Dmitry Baryshkov
@ 2024-05-30 23:14 ` Abhinav Kumar
0 siblings, 0 replies; 50+ messages in thread
From: Abhinav Kumar @ 2024-05-30 23:14 UTC (permalink / raw)
To: Dmitry Baryshkov, Rob Clark, Sean Paul, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> Use the drm_rect_fp_to_int() helper instead of using the hand-written
> code.
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 7 +------
> 1 file changed, 1 insertion(+), 6 deletions(-)
>
Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v4 03/13] drm/msm/dpu: move pstate->pipe initialization to dpu_plane_atomic_check
2024-03-14 0:02 [PATCH v4 00/13] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
2024-03-14 0:02 ` [PATCH v4 01/13] drm/msm/dpu: take plane rotation into account for " Dmitry Baryshkov
2024-03-14 0:02 ` [PATCH v4 02/13] drm/msm/dpu: use drm_rect_fp_to_int() Dmitry Baryshkov
@ 2024-03-14 0:02 ` Dmitry Baryshkov
2024-05-31 0:28 ` Abhinav Kumar
2024-03-14 0:02 ` [PATCH v4 04/13] drm/msm/dpu: drop virt_formats from SSPP subblock configuration Dmitry Baryshkov
` (10 subsequent siblings)
13 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-03-14 0:02 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Abhinav Kumar, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
In preparation for virtualized planes support, move pstate->pipe
initialization from dpu_plane_reset() to dpu_plane_atomic_check(). In
case of virtual planes the plane's pipe will not be known up to the
point of atomic_check() callback.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 26 +++++++++++------------
1 file changed, 12 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index 9c52fe3c0261..70d6a8989e1a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -795,6 +795,7 @@ static int dpu_plane_atomic_check(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_kms *dpu_kms = _dpu_plane_get_kms(plane);
struct dpu_sw_pipe *pipe = &pstate->pipe;
struct dpu_sw_pipe *r_pipe = &pstate->r_pipe;
const struct drm_crtc_state *crtc_state = NULL;
@@ -805,13 +806,22 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
uint32_t max_linewidth;
unsigned int rotation;
uint32_t supported_rotations;
- const struct dpu_sspp_cfg *pipe_hw_caps = pstate->pipe.sspp->cap;
- const struct dpu_sspp_sub_blks *sblk = pstate->pipe.sspp->cap->sblk;
+ const struct dpu_sspp_cfg *pipe_hw_caps;
+ const struct dpu_sspp_sub_blks *sblk;
if (new_plane_state->crtc)
crtc_state = drm_atomic_get_new_crtc_state(state,
new_plane_state->crtc);
+ pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
+ r_pipe->sspp = NULL;
+
+ if (!pipe->sspp)
+ return -EINVAL;
+
+ pipe_hw_caps = pipe->sspp->cap;
+ sblk = pipe->sspp->cap->sblk;
+
min_scale = FRAC_16_16(1, sblk->maxupscale);
ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
min_scale,
@@ -828,7 +838,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
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) {
@@ -1292,7 +1301,6 @@ static void dpu_plane_reset(struct drm_plane *plane)
{
struct dpu_plane *pdpu;
struct dpu_plane_state *pstate;
- struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);
if (!plane) {
DPU_ERROR("invalid plane\n");
@@ -1314,16 +1322,6 @@ static void dpu_plane_reset(struct drm_plane *plane)
return;
}
- /*
- * Set the SSPP here until we have proper virtualized DPU planes.
- * 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);
}
--
2.39.2
^ permalink raw reply related [flat|nested] 50+ messages in thread* Re: [PATCH v4 03/13] drm/msm/dpu: move pstate->pipe initialization to dpu_plane_atomic_check
2024-03-14 0:02 ` [PATCH v4 03/13] drm/msm/dpu: move pstate->pipe initialization to dpu_plane_atomic_check Dmitry Baryshkov
@ 2024-05-31 0:28 ` Abhinav Kumar
0 siblings, 0 replies; 50+ messages in thread
From: Abhinav Kumar @ 2024-05-31 0:28 UTC (permalink / raw)
To: Dmitry Baryshkov, Rob Clark, Sean Paul, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> In preparation for virtualized planes support, move pstate->pipe
> initialization from dpu_plane_reset() to dpu_plane_atomic_check(). In
> case of virtual planes the plane's pipe will not be known up to the
> point of atomic_check() callback.
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 26 +++++++++++------------
> 1 file changed, 12 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> index 9c52fe3c0261..70d6a8989e1a 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> @@ -795,6 +795,7 @@ static int dpu_plane_atomic_check(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_kms *dpu_kms = _dpu_plane_get_kms(plane);
We already have kms from a few lines above. No need for getting it again.
Rest LGTM.
> struct dpu_sw_pipe *pipe = &pstate->pipe;
> struct dpu_sw_pipe *r_pipe = &pstate->r_pipe;
> const struct drm_crtc_state *crtc_state = NULL;
> @@ -805,13 +806,22 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> uint32_t max_linewidth;
> unsigned int rotation;
> uint32_t supported_rotations;
> - const struct dpu_sspp_cfg *pipe_hw_caps = pstate->pipe.sspp->cap;
> - const struct dpu_sspp_sub_blks *sblk = pstate->pipe.sspp->cap->sblk;
> + const struct dpu_sspp_cfg *pipe_hw_caps;
> + const struct dpu_sspp_sub_blks *sblk;
>
> if (new_plane_state->crtc)
> crtc_state = drm_atomic_get_new_crtc_state(state,
> new_plane_state->crtc);
>
> + pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
> + r_pipe->sspp = NULL;
> +
> + if (!pipe->sspp)
> + return -EINVAL;
> +
> + pipe_hw_caps = pipe->sspp->cap;
> + sblk = pipe->sspp->cap->sblk;
> +
> min_scale = FRAC_16_16(1, sblk->maxupscale);
> ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
> min_scale,
> @@ -828,7 +838,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> 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) {
> @@ -1292,7 +1301,6 @@ static void dpu_plane_reset(struct drm_plane *plane)
> {
> struct dpu_plane *pdpu;
> struct dpu_plane_state *pstate;
> - struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);
>
> if (!plane) {
> DPU_ERROR("invalid plane\n");
> @@ -1314,16 +1322,6 @@ static void dpu_plane_reset(struct drm_plane *plane)
> return;
> }
>
> - /*
> - * Set the SSPP here until we have proper virtualized DPU planes.
> - * 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);
> }
>
^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v4 04/13] drm/msm/dpu: drop virt_formats from SSPP subblock configuration
2024-03-14 0:02 [PATCH v4 00/13] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
` (2 preceding siblings ...)
2024-03-14 0:02 ` [PATCH v4 03/13] drm/msm/dpu: move pstate->pipe initialization to dpu_plane_atomic_check Dmitry Baryshkov
@ 2024-03-14 0:02 ` Dmitry Baryshkov
2024-05-31 0:32 ` Abhinav Kumar
2024-03-14 0:02 ` [PATCH v4 05/13] drm/msm/dpu: move scaling limitations out of the hw_catalog Dmitry Baryshkov
` (9 subsequent siblings)
13 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-03-14 0:02 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Abhinav Kumar, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
The virt_formats / virt_num_formats are not used by the current driver
and are not going to be used in future since formats for virtual planes
are handled in a different way, by forbidding unsupported combinations
during atomic_check. Drop those fields now.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 8 --------
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 4 ----
2 files changed, 12 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
index f2b6eac7601d..a2e4832aa25d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
@@ -289,8 +289,6 @@ static const u32 wb2_formats_rgb_yuv[] = {
.base = 0x1a00, .len = 0x100,}, \
.format_list = plane_formats_yuv, \
.num_formats = ARRAY_SIZE(plane_formats_yuv), \
- .virt_format_list = plane_formats, \
- .virt_num_formats = ARRAY_SIZE(plane_formats), \
.rotation_cfg = NULL, \
}
@@ -305,8 +303,6 @@ static const u32 wb2_formats_rgb_yuv[] = {
.base = 0x1a00, .len = 0x100,}, \
.format_list = plane_formats_yuv, \
.num_formats = ARRAY_SIZE(plane_formats_yuv), \
- .virt_format_list = plane_formats, \
- .virt_num_formats = ARRAY_SIZE(plane_formats), \
.rotation_cfg = rot_cfg, \
}
@@ -316,8 +312,6 @@ static const u32 wb2_formats_rgb_yuv[] = {
.maxupscale = SSPP_UNITY_SCALE, \
.format_list = plane_formats_yuv, \
.num_formats = ARRAY_SIZE(plane_formats_yuv), \
- .virt_format_list = plane_formats, \
- .virt_num_formats = ARRAY_SIZE(plane_formats), \
}
#define _DMA_SBLK() \
@@ -326,8 +320,6 @@ static const u32 wb2_formats_rgb_yuv[] = {
.maxupscale = SSPP_UNITY_SCALE, \
.format_list = plane_formats, \
.num_formats = ARRAY_SIZE(plane_formats), \
- .virt_format_list = plane_formats, \
- .virt_num_formats = ARRAY_SIZE(plane_formats), \
}
static const struct dpu_rotation_cfg dpu_rot_sc7280_cfg_v2 = {
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 d1aef778340b..addf8e932d12 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
@@ -372,8 +372,6 @@ struct dpu_caps {
* @csc_blk:
* @format_list: Pointer to list of supported formats
* @num_formats: Number of supported formats
- * @virt_format_list: Pointer to list of supported formats for virtual planes
- * @virt_num_formats: Number of supported formats for virtual planes
* @dpu_rotation_cfg: inline rotation configuration
*/
struct dpu_sspp_sub_blks {
@@ -386,8 +384,6 @@ struct dpu_sspp_sub_blks {
const u32 *format_list;
u32 num_formats;
- const u32 *virt_format_list;
- u32 virt_num_formats;
const struct dpu_rotation_cfg *rotation_cfg;
};
--
2.39.2
^ permalink raw reply related [flat|nested] 50+ messages in thread* Re: [PATCH v4 04/13] drm/msm/dpu: drop virt_formats from SSPP subblock configuration
2024-03-14 0:02 ` [PATCH v4 04/13] drm/msm/dpu: drop virt_formats from SSPP subblock configuration Dmitry Baryshkov
@ 2024-05-31 0:32 ` Abhinav Kumar
0 siblings, 0 replies; 50+ messages in thread
From: Abhinav Kumar @ 2024-05-31 0:32 UTC (permalink / raw)
To: Dmitry Baryshkov, Rob Clark, Sean Paul, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> The virt_formats / virt_num_formats are not used by the current driver
> and are not going to be used in future since formats for virtual planes
> are handled in a different way, by forbidding unsupported combinations
> during atomic_check. Drop those fields now.
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 8 --------
> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 4 ----
> 2 files changed, 12 deletions(-)
>
Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v4 05/13] drm/msm/dpu: move scaling limitations out of the hw_catalog
2024-03-14 0:02 [PATCH v4 00/13] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
` (3 preceding siblings ...)
2024-03-14 0:02 ` [PATCH v4 04/13] drm/msm/dpu: drop virt_formats from SSPP subblock configuration Dmitry Baryshkov
@ 2024-03-14 0:02 ` Dmitry Baryshkov
2024-05-31 1:02 ` Abhinav Kumar
2024-03-14 0:02 ` [PATCH v4 06/13] drm/msm/dpu: split dpu_plane_atomic_check() Dmitry Baryshkov
` (8 subsequent siblings)
13 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-03-14 0:02 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Abhinav Kumar, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
Max upscale / downscale factors are constant between platforms. In
preparation to adding support for virtual planes and allocating SSPP
blocks on demand move max scaling factors out of the HW catalog and
handle them in the dpu_plane directly. If any of the scaling blocks gets
different limitations, this will have to be handled separately, after
the plane refactoring.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 12 ------------
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 4 ----
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 16 +++++++++++++---
3 files changed, 13 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
index a2e4832aa25d..47fd8baf53e6 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
@@ -113,10 +113,6 @@
#define MAX_HORZ_DECIMATION 4
#define MAX_VERT_DECIMATION 4
-#define MAX_UPSCALE_RATIO 20
-#define MAX_DOWNSCALE_RATIO 4
-#define SSPP_UNITY_SCALE 1
-
#define STRCAT(X, Y) (X Y)
static const uint32_t plane_formats[] = {
@@ -280,8 +276,6 @@ static const u32 wb2_formats_rgb_yuv[] = {
/* SSPP common configuration */
#define _VIG_SBLK(scaler_ver) \
{ \
- .maxdwnscale = MAX_DOWNSCALE_RATIO, \
- .maxupscale = MAX_UPSCALE_RATIO, \
.scaler_blk = {.name = "scaler", \
.version = scaler_ver, \
.base = 0xa00, .len = 0xa0,}, \
@@ -294,8 +288,6 @@ static const u32 wb2_formats_rgb_yuv[] = {
#define _VIG_SBLK_ROT(scaler_ver, rot_cfg) \
{ \
- .maxdwnscale = MAX_DOWNSCALE_RATIO, \
- .maxupscale = MAX_UPSCALE_RATIO, \
.scaler_blk = {.name = "scaler", \
.version = scaler_ver, \
.base = 0xa00, .len = 0xa0,}, \
@@ -308,16 +300,12 @@ static const u32 wb2_formats_rgb_yuv[] = {
#define _VIG_SBLK_NOSCALE() \
{ \
- .maxdwnscale = SSPP_UNITY_SCALE, \
- .maxupscale = SSPP_UNITY_SCALE, \
.format_list = plane_formats_yuv, \
.num_formats = ARRAY_SIZE(plane_formats_yuv), \
}
#define _DMA_SBLK() \
{ \
- .maxdwnscale = SSPP_UNITY_SCALE, \
- .maxupscale = SSPP_UNITY_SCALE, \
.format_list = plane_formats, \
.num_formats = ARRAY_SIZE(plane_formats), \
}
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 addf8e932d12..fc7da6e1feeb 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
@@ -364,8 +364,6 @@ struct dpu_caps {
/**
* struct dpu_sspp_sub_blks : SSPP sub-blocks
* common: Pointer to common configurations shared by sub blocks
- * @maxdwnscale: max downscale ratio supported(without DECIMATION)
- * @maxupscale: maxupscale ratio supported
* @max_per_pipe_bw: maximum allowable bandwidth of this pipe in kBps
* @qseed_ver: qseed version
* @scaler_blk:
@@ -375,8 +373,6 @@ struct dpu_caps {
* @dpu_rotation_cfg: inline rotation configuration
*/
struct dpu_sspp_sub_blks {
- u32 maxdwnscale;
- u32 maxupscale;
u32 max_per_pipe_bw;
u32 qseed_ver;
struct dpu_scaler_blk scaler_blk;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index 70d6a8989e1a..6360052523b5 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -785,12 +785,15 @@ static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu,
return 0;
}
+#define MAX_UPSCALE_RATIO 20
+#define MAX_DOWNSCALE_RATIO 4
+
static int dpu_plane_atomic_check(struct drm_plane *plane,
struct drm_atomic_state *state)
{
struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
plane);
- int ret = 0, min_scale;
+ int ret = 0, min_scale, max_scale;
struct dpu_plane *pdpu = to_dpu_plane(plane);
struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);
u64 max_mdp_clk_rate = kms->perf.max_core_clk_rate;
@@ -822,10 +825,17 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
pipe_hw_caps = pipe->sspp->cap;
sblk = pipe->sspp->cap->sblk;
- min_scale = FRAC_16_16(1, sblk->maxupscale);
+ if (sblk->scaler_blk.len) {
+ min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
+ max_scale = MAX_DOWNSCALE_RATIO << 16;
+ } else {
+ min_scale = 1 << 16;
+ max_scale = 1 << 16;
+ }
+
ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
min_scale,
- sblk->maxdwnscale << 16,
+ max_scale,
true, true);
if (ret) {
DPU_DEBUG_PLANE(pdpu, "Check plane state failed (%d)\n", ret);
--
2.39.2
^ permalink raw reply related [flat|nested] 50+ messages in thread* Re: [PATCH v4 05/13] drm/msm/dpu: move scaling limitations out of the hw_catalog
2024-03-14 0:02 ` [PATCH v4 05/13] drm/msm/dpu: move scaling limitations out of the hw_catalog Dmitry Baryshkov
@ 2024-05-31 1:02 ` Abhinav Kumar
2024-05-31 8:16 ` Dmitry Baryshkov
0 siblings, 1 reply; 50+ messages in thread
From: Abhinav Kumar @ 2024-05-31 1:02 UTC (permalink / raw)
To: Dmitry Baryshkov, Rob Clark, Sean Paul, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> Max upscale / downscale factors are constant between platforms. In
> preparation to adding support for virtual planes and allocating SSPP
> blocks on demand move max scaling factors out of the HW catalog and
> handle them in the dpu_plane directly. If any of the scaling blocks gets
> different limitations, this will have to be handled separately, after
> the plane refactoring.
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 12 ------------
> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 4 ----
> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 16 +++++++++++++---
> 3 files changed, 13 insertions(+), 19 deletions(-)
>
<Snip>
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> index 70d6a8989e1a..6360052523b5 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> @@ -785,12 +785,15 @@ static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu,
> return 0;
> }
>
> +#define MAX_UPSCALE_RATIO 20
> +#define MAX_DOWNSCALE_RATIO 4
> +
> static int dpu_plane_atomic_check(struct drm_plane *plane,
> struct drm_atomic_state *state)
> {
> struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> plane);
> - int ret = 0, min_scale;
> + int ret = 0, min_scale, max_scale;
> struct dpu_plane *pdpu = to_dpu_plane(plane);
> struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);
> u64 max_mdp_clk_rate = kms->perf.max_core_clk_rate;
> @@ -822,10 +825,17 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> pipe_hw_caps = pipe->sspp->cap;
> sblk = pipe->sspp->cap->sblk;
>
> - min_scale = FRAC_16_16(1, sblk->maxupscale);
> + if (sblk->scaler_blk.len) {
> + min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
> + max_scale = MAX_DOWNSCALE_RATIO << 16;
> + } else {
> + min_scale = 1 << 16;
> + max_scale = 1 << 16;
You can use DRM_PLANE_NO_SCALING instead.
> + }
> +
> ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
> min_scale,
> - sblk->maxdwnscale << 16,
> + max_scale,
> true, true);
I am missing something here.
As per the documentation of this API, min and max are the scaling limits
of both directions and not max_upscale and max_downscale.
**
837 * drm_atomic_helper_check_plane_state() - Check plane state for
validity
838 * @plane_state: plane state to check
839 * @crtc_state: CRTC state to check
840 * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point
841 * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point
842 * @can_position: is it legal to position the plane such that it
But this change is passing max_upscale and max_downscale as the min and
max resp. Isnt that wrong?
> if (ret) {
> DPU_DEBUG_PLANE(pdpu, "Check plane state failed (%d)\n", ret);
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 05/13] drm/msm/dpu: move scaling limitations out of the hw_catalog
2024-05-31 1:02 ` Abhinav Kumar
@ 2024-05-31 8:16 ` Dmitry Baryshkov
2024-05-31 19:20 ` Abhinav Kumar
0 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-05-31 8:16 UTC (permalink / raw)
To: Abhinav Kumar
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On Fri, 31 May 2024 at 04:02, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>
>
>
> On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> > Max upscale / downscale factors are constant between platforms. In
> > preparation to adding support for virtual planes and allocating SSPP
> > blocks on demand move max scaling factors out of the HW catalog and
> > handle them in the dpu_plane directly. If any of the scaling blocks gets
> > different limitations, this will have to be handled separately, after
> > the plane refactoring.
> >
> > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > ---
> > drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 12 ------------
> > drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 4 ----
> > drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 16 +++++++++++++---
> > 3 files changed, 13 insertions(+), 19 deletions(-)
> >
>
> <Snip>
>
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > index 70d6a8989e1a..6360052523b5 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > @@ -785,12 +785,15 @@ static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu,
> > return 0;
> > }
> >
> > +#define MAX_UPSCALE_RATIO 20
> > +#define MAX_DOWNSCALE_RATIO 4
> > +
> > static int dpu_plane_atomic_check(struct drm_plane *plane,
> > struct drm_atomic_state *state)
> > {
> > struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> > plane);
> > - int ret = 0, min_scale;
> > + int ret = 0, min_scale, max_scale;
> > struct dpu_plane *pdpu = to_dpu_plane(plane);
> > struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);
> > u64 max_mdp_clk_rate = kms->perf.max_core_clk_rate;
> > @@ -822,10 +825,17 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> > pipe_hw_caps = pipe->sspp->cap;
> > sblk = pipe->sspp->cap->sblk;
> >
> > - min_scale = FRAC_16_16(1, sblk->maxupscale);
> > + if (sblk->scaler_blk.len) {
> > + min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
> > + max_scale = MAX_DOWNSCALE_RATIO << 16;
> > + } else {
> > + min_scale = 1 << 16;
> > + max_scale = 1 << 16;
>
> You can use DRM_PLANE_NO_SCALING instead.
Ack
>
> > + }
> > +
> > ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
> > min_scale,
> > - sblk->maxdwnscale << 16,
> > + max_scale,
> > true, true);
>
> I am missing something here.
>
> As per the documentation of this API, min and max are the scaling limits
> of both directions and not max_upscale and max_downscale.
>
> **
> 837 * drm_atomic_helper_check_plane_state() - Check plane state for
> validity
> 838 * @plane_state: plane state to check
> 839 * @crtc_state: CRTC state to check
> 840 * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point
> 841 * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point
> 842 * @can_position: is it legal to position the plane such that it
>
>
> But this change is passing max_upscale and max_downscale as the min and
> max resp. Isnt that wrong?
First of all, please notice that I'm not changing the values that are
passed to the function. What was being passed beforehand gets passed
after this commit. I just moved it out of the catalog.
Second, if we take a look at drm_calc_scale(), we can see that it
calculates src / dst and checks that it is within the min_scale and
max_scale boundaries, just like documented.
In our case, the boundaries are (I'm omitting 16.16 math):
- upscale 20 times. dst = 20 * src, scale = src/dst = 1/20
- downscale 4 times. dst = 1/4 * src, scale = src/dst = 4
So, from the point of view of drm_calc_scale(), the min_scale is
1/MAX_UPSCALE, max_scale = MAX_DOWNSCALE and the values the code is
passing are correct.
>
>
> > if (ret) {
> > DPU_DEBUG_PLANE(pdpu, "Check plane state failed (%d)\n", ret);
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 05/13] drm/msm/dpu: move scaling limitations out of the hw_catalog
2024-05-31 8:16 ` Dmitry Baryshkov
@ 2024-05-31 19:20 ` Abhinav Kumar
2024-05-31 19:45 ` Dmitry Baryshkov
0 siblings, 1 reply; 50+ messages in thread
From: Abhinav Kumar @ 2024-05-31 19:20 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On 5/31/2024 1:16 AM, Dmitry Baryshkov wrote:
> On Fri, 31 May 2024 at 04:02, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>>
>>
>>
>> On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
>>> Max upscale / downscale factors are constant between platforms. In
>>> preparation to adding support for virtual planes and allocating SSPP
>>> blocks on demand move max scaling factors out of the HW catalog and
>>> handle them in the dpu_plane directly. If any of the scaling blocks gets
>>> different limitations, this will have to be handled separately, after
>>> the plane refactoring.
>>>
>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>> ---
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 12 ------------
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 4 ----
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 16 +++++++++++++---
>>> 3 files changed, 13 insertions(+), 19 deletions(-)
>>>
>>
>> <Snip>
>>
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>> index 70d6a8989e1a..6360052523b5 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>> @@ -785,12 +785,15 @@ static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu,
>>> return 0;
>>> }
>>>
>>> +#define MAX_UPSCALE_RATIO 20
>>> +#define MAX_DOWNSCALE_RATIO 4
>>> +
>>> static int dpu_plane_atomic_check(struct drm_plane *plane,
>>> struct drm_atomic_state *state)
>>> {
>>> struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
>>> plane);
>>> - int ret = 0, min_scale;
>>> + int ret = 0, min_scale, max_scale;
>>> struct dpu_plane *pdpu = to_dpu_plane(plane);
>>> struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);
>>> u64 max_mdp_clk_rate = kms->perf.max_core_clk_rate;
>>> @@ -822,10 +825,17 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
>>> pipe_hw_caps = pipe->sspp->cap;
>>> sblk = pipe->sspp->cap->sblk;
>>>
>>> - min_scale = FRAC_16_16(1, sblk->maxupscale);
>>> + if (sblk->scaler_blk.len) {
>>> + min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
>>> + max_scale = MAX_DOWNSCALE_RATIO << 16;
>>> + } else {
>>> + min_scale = 1 << 16;
>>> + max_scale = 1 << 16;
>>
>> You can use DRM_PLANE_NO_SCALING instead.
>
> Ack
>
>>
>>> + }
>>> +
>>> ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
>>> min_scale,
>>> - sblk->maxdwnscale << 16,
>>> + max_scale,
>>> true, true);
>>
>> I am missing something here.
>>
>> As per the documentation of this API, min and max are the scaling limits
>> of both directions and not max_upscale and max_downscale.
>>
>> **
>> 837 * drm_atomic_helper_check_plane_state() - Check plane state for
>> validity
>> 838 * @plane_state: plane state to check
>> 839 * @crtc_state: CRTC state to check
>> 840 * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point
>> 841 * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point
>> 842 * @can_position: is it legal to position the plane such that it
>>
>>
>> But this change is passing max_upscale and max_downscale as the min and
>> max resp. Isnt that wrong?
>
> First of all, please notice that I'm not changing the values that are
> passed to the function. What was being passed beforehand gets passed
> after this commit. I just moved it out of the catalog.
>
Ack.
> Second, if we take a look at drm_calc_scale(), we can see that it
> calculates src / dst and checks that it is within the min_scale and
> max_scale boundaries, just like documented.
> In our case, the boundaries are (I'm omitting 16.16 math):
> - upscale 20 times. dst = 20 * src, scale = src/dst = 1/20
> - downscale 4 times. dst = 1/4 * src, scale = src/dst = 4
>
> So, from the point of view of drm_calc_scale(), the min_scale is
> 1/MAX_UPSCALE, max_scale = MAX_DOWNSCALE and the values the code is
> passing are correct.
>
That part is fine. Agreed.
But I do think, that API is not correct if the scaling limits are
different in the Horizontal Vs Vertical direction as today it assumes
the limits are same in both. Anyway, thats outside the scope of this
patch. So I am good for now.
>>
>>
>>> if (ret) {
>>> DPU_DEBUG_PLANE(pdpu, "Check plane state failed (%d)\n", ret);
>
>
>
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 05/13] drm/msm/dpu: move scaling limitations out of the hw_catalog
2024-05-31 19:20 ` Abhinav Kumar
@ 2024-05-31 19:45 ` Dmitry Baryshkov
0 siblings, 0 replies; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-05-31 19:45 UTC (permalink / raw)
To: Abhinav Kumar
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On Fri, May 31, 2024 at 12:20:24PM -0700, Abhinav Kumar wrote:
>
>
> On 5/31/2024 1:16 AM, Dmitry Baryshkov wrote:
> > On Fri, 31 May 2024 at 04:02, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
> > >
> > >
> > >
> > > On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> > > > Max upscale / downscale factors are constant between platforms. In
> > > > preparation to adding support for virtual planes and allocating SSPP
> > > > blocks on demand move max scaling factors out of the HW catalog and
> > > > handle them in the dpu_plane directly. If any of the scaling blocks gets
> > > > different limitations, this will have to be handled separately, after
> > > > the plane refactoring.
> > > >
> > > > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > ---
> > > > drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 12 ------------
> > > > drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 4 ----
> > > > drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 16 +++++++++++++---
> > > > 3 files changed, 13 insertions(+), 19 deletions(-)
> > > >
> > >
> > > <Snip>
> > >
> > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > index 70d6a8989e1a..6360052523b5 100644
> > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > @@ -785,12 +785,15 @@ static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu,
> > > > return 0;
> > > > }
> > > >
> > > > +#define MAX_UPSCALE_RATIO 20
> > > > +#define MAX_DOWNSCALE_RATIO 4
> > > > +
> > > > static int dpu_plane_atomic_check(struct drm_plane *plane,
> > > > struct drm_atomic_state *state)
> > > > {
> > > > struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> > > > plane);
> > > > - int ret = 0, min_scale;
> > > > + int ret = 0, min_scale, max_scale;
> > > > struct dpu_plane *pdpu = to_dpu_plane(plane);
> > > > struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);
> > > > u64 max_mdp_clk_rate = kms->perf.max_core_clk_rate;
> > > > @@ -822,10 +825,17 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> > > > pipe_hw_caps = pipe->sspp->cap;
> > > > sblk = pipe->sspp->cap->sblk;
> > > >
> > > > - min_scale = FRAC_16_16(1, sblk->maxupscale);
> > > > + if (sblk->scaler_blk.len) {
> > > > + min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
> > > > + max_scale = MAX_DOWNSCALE_RATIO << 16;
> > > > + } else {
> > > > + min_scale = 1 << 16;
> > > > + max_scale = 1 << 16;
> > >
> > > You can use DRM_PLANE_NO_SCALING instead.
> >
> > Ack
> >
> > >
> > > > + }
> > > > +
> > > > ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
> > > > min_scale,
> > > > - sblk->maxdwnscale << 16,
> > > > + max_scale,
> > > > true, true);
> > >
> > > I am missing something here.
> > >
> > > As per the documentation of this API, min and max are the scaling limits
> > > of both directions and not max_upscale and max_downscale.
> > >
> > > **
> > > 837 * drm_atomic_helper_check_plane_state() - Check plane state for
> > > validity
> > > 838 * @plane_state: plane state to check
> > > 839 * @crtc_state: CRTC state to check
> > > 840 * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point
> > > 841 * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point
> > > 842 * @can_position: is it legal to position the plane such that it
> > >
> > >
> > > But this change is passing max_upscale and max_downscale as the min and
> > > max resp. Isnt that wrong?
> >
> > First of all, please notice that I'm not changing the values that are
> > passed to the function. What was being passed beforehand gets passed
> > after this commit. I just moved it out of the catalog.
> >
>
> Ack.
>
> > Second, if we take a look at drm_calc_scale(), we can see that it
> > calculates src / dst and checks that it is within the min_scale and
> > max_scale boundaries, just like documented.
> > In our case, the boundaries are (I'm omitting 16.16 math):
> > - upscale 20 times. dst = 20 * src, scale = src/dst = 1/20
> > - downscale 4 times. dst = 1/4 * src, scale = src/dst = 4
> >
> > So, from the point of view of drm_calc_scale(), the min_scale is
> > 1/MAX_UPSCALE, max_scale = MAX_DOWNSCALE and the values the code is
> > passing are correct.
> >
>
> That part is fine. Agreed.
>
> But I do think, that API is not correct if the scaling limits are different
> in the Horizontal Vs Vertical direction as today it assumes the limits are
> same in both.
Agree. But if we ever need to support different scaling limits, it would
be easy to extend the API.
> Anyway, thats outside the scope of this patch. So I am good
> for now.
>
> > >
> > >
> > > > if (ret) {
> > > > DPU_DEBUG_PLANE(pdpu, "Check plane state failed (%d)\n", ret);
> >
> >
> >
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v4 06/13] drm/msm/dpu: split dpu_plane_atomic_check()
2024-03-14 0:02 [PATCH v4 00/13] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
` (4 preceding siblings ...)
2024-03-14 0:02 ` [PATCH v4 05/13] drm/msm/dpu: move scaling limitations out of the hw_catalog Dmitry Baryshkov
@ 2024-03-14 0:02 ` Dmitry Baryshkov
2024-06-05 23:19 ` Abhinav Kumar
2024-03-14 0:02 ` [PATCH v4 07/13] drm/msm/dpu: move rot90 checking to dpu_plane_atomic_check_pipe() Dmitry Baryshkov
` (7 subsequent siblings)
13 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-03-14 0:02 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Abhinav Kumar, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
Split dpu_plane_atomic_check() function into two pieces:
dpu_plane_atomic_check_nopipe() performing generic checks on the pstate,
without touching the associated pipe,
and
dpu_plane_atomic_check_pipes(), which takes into account used pipes.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 184 ++++++++++++++--------
1 file changed, 117 insertions(+), 67 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index 6360052523b5..187ac2767a2b 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -788,50 +788,22 @@ static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu,
#define MAX_UPSCALE_RATIO 20
#define MAX_DOWNSCALE_RATIO 4
-static int dpu_plane_atomic_check(struct drm_plane *plane,
- struct drm_atomic_state *state)
+static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
+ struct drm_plane_state *new_plane_state,
+ const struct drm_crtc_state *crtc_state)
{
- struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
- plane);
int ret = 0, min_scale, max_scale;
struct dpu_plane *pdpu = to_dpu_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_kms *dpu_kms = _dpu_plane_get_kms(plane);
- 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;
- uint32_t supported_rotations;
- const struct dpu_sspp_cfg *pipe_hw_caps;
- const struct dpu_sspp_sub_blks *sblk;
- if (new_plane_state->crtc)
- crtc_state = drm_atomic_get_new_crtc_state(state,
- new_plane_state->crtc);
-
- pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
- r_pipe->sspp = NULL;
-
- if (!pipe->sspp)
- return -EINVAL;
-
- pipe_hw_caps = pipe->sspp->cap;
- sblk = pipe->sspp->cap->sblk;
-
- if (sblk->scaler_blk.len) {
- min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
- max_scale = MAX_DOWNSCALE_RATIO << 16;
- } else {
- min_scale = 1 << 16;
- max_scale = 1 << 16;
- }
+ min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
+ max_scale = MAX_DOWNSCALE_RATIO << 16;
ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
min_scale,
@@ -844,11 +816,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
if (!new_plane_state->visible)
return 0;
- 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;
-
pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos;
if (pstate->stage >= pdpu->catalog->caps->max_mixer_blendstages) {
DPU_ERROR("> %d plane stages assigned\n",
@@ -872,8 +839,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
return -E2BIG;
}
- fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
-
max_linewidth = pdpu->catalog->caps->max_linewidth;
drm_rect_rotate(&pipe_cfg->src_rect,
@@ -882,6 +847,83 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
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;
+ }
+
+ *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));
+ }
+
+ drm_rect_rotate_inv(&pipe_cfg->src_rect,
+ new_plane_state->fb->width, new_plane_state->fb->height,
+ new_plane_state->rotation);
+ if (r_pipe_cfg->src_rect.x1 != 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;
+}
+
+static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
+ struct drm_atomic_state *state,
+ const struct drm_crtc_state *crtc_state)
+{
+ struct drm_plane_state *new_plane_state =
+ 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;
+ 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;
+ uint32_t max_linewidth;
+ unsigned int rotation;
+ uint32_t supported_rotations;
+ const struct dpu_sspp_cfg *pipe_hw_caps;
+ const struct dpu_sspp_sub_blks *sblk;
+ int ret = 0;
+
+ pipe_hw_caps = pipe->sspp->cap;
+ sblk = pipe->sspp->cap->sblk;
+
+ /*
+ * We already have verified scaling against platform limitations.
+ * Now check if the SSPP supports scaling at all.
+ */
+ if (!sblk->scaler_blk.len &&
+ ((drm_rect_width(&new_plane_state->src) >> 16 !=
+ drm_rect_width(&new_plane_state->dst)) ||
+ (drm_rect_height(&new_plane_state->src) >> 16 !=
+ drm_rect_height(&new_plane_state->dst))))
+ return -ERANGE;
+
+ 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;
+
+ fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
+
+ max_linewidth = pdpu->catalog->caps->max_linewidth;
+
+ ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt,
+ &crtc_state->adjusted_mode);
+ if (ret)
+ return ret;
+
+ if (r_pipe_cfg->src_rect.x1 != 0) {
/*
* In parallel multirect case only the half of the usual width
* is supported for tiled formats. If we are here, we know that
@@ -895,12 +937,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
return -E2BIG;
}
- 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;
- }
-
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) &&
@@ -922,26 +958,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
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;
- }
-
- drm_rect_rotate_inv(&pipe_cfg->src_rect,
- new_plane_state->fb->width, new_plane_state->fb->height,
- new_plane_state->rotation);
- if (r_pipe->sspp)
- drm_rect_rotate_inv(&r_pipe_cfg->src_rect,
- new_plane_state->fb->width, new_plane_state->fb->height,
- new_plane_state->rotation);
-
- ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt, &crtc_state->adjusted_mode);
- if (ret)
- return ret;
-
- if (r_pipe->sspp) {
ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, fmt,
&crtc_state->adjusted_mode);
if (ret)
@@ -964,11 +980,45 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
}
pstate->rotation = rotation;
- pstate->needs_qos_remap = drm_atomic_crtc_needs_modeset(crtc_state);
return 0;
}
+static int dpu_plane_atomic_check(struct drm_plane *plane,
+ struct drm_atomic_state *state)
+{
+ struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
+ plane);
+ int ret = 0;
+ 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;
+ const struct drm_crtc_state *crtc_state = NULL;
+
+ if (new_plane_state->crtc)
+ crtc_state = drm_atomic_get_new_crtc_state(state,
+ new_plane_state->crtc);
+
+ if (pdpu->pipe != SSPP_NONE) {
+ pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
+ r_pipe->sspp = NULL;
+ }
+
+ if (!pipe->sspp)
+ return -EINVAL;
+
+ ret = dpu_plane_atomic_check_nopipe(plane, new_plane_state, crtc_state);
+ if (ret)
+ return ret;
+
+ if (!new_plane_state->visible)
+ return 0;
+
+ return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
+}
+
static void dpu_plane_flush_csc(struct dpu_plane *pdpu, struct dpu_sw_pipe *pipe)
{
const struct dpu_format *format =
--
2.39.2
^ permalink raw reply related [flat|nested] 50+ messages in thread* Re: [PATCH v4 06/13] drm/msm/dpu: split dpu_plane_atomic_check()
2024-03-14 0:02 ` [PATCH v4 06/13] drm/msm/dpu: split dpu_plane_atomic_check() Dmitry Baryshkov
@ 2024-06-05 23:19 ` Abhinav Kumar
2024-06-05 23:32 ` Dmitry Baryshkov
0 siblings, 1 reply; 50+ messages in thread
From: Abhinav Kumar @ 2024-06-05 23:19 UTC (permalink / raw)
To: Dmitry Baryshkov, Rob Clark, Sean Paul, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> Split dpu_plane_atomic_check() function into two pieces:
>
> dpu_plane_atomic_check_nopipe() performing generic checks on the pstate,
> without touching the associated pipe,
>
> and
>
> dpu_plane_atomic_check_pipes(), which takes into account used pipes.
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 184 ++++++++++++++--------
> 1 file changed, 117 insertions(+), 67 deletions(-)
>
One thing which seemed odd to me is even dpu_plane_atomic_check_nopipe()
does use pipe_cfg even though its named "nopipe".
Perhaps were you targetting a split of SW planes vs SSPP atomic_check?
I tried applying this patch on top of msm-next to more closely review
the split up but it does not apply. So, I will review this patch a
little better after it is re-spun. But will proceed with remaining patches.
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> index 6360052523b5..187ac2767a2b 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> @@ -788,50 +788,22 @@ static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu,
> #define MAX_UPSCALE_RATIO 20
> #define MAX_DOWNSCALE_RATIO 4
>
> -static int dpu_plane_atomic_check(struct drm_plane *plane,
> - struct drm_atomic_state *state)
> +static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
> + struct drm_plane_state *new_plane_state,
> + const struct drm_crtc_state *crtc_state)
> {
> - struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> - plane);
> int ret = 0, min_scale, max_scale;
> struct dpu_plane *pdpu = to_dpu_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_kms *dpu_kms = _dpu_plane_get_kms(plane);
> - 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;
> - uint32_t supported_rotations;
> - const struct dpu_sspp_cfg *pipe_hw_caps;
> - const struct dpu_sspp_sub_blks *sblk;
>
> - if (new_plane_state->crtc)
> - crtc_state = drm_atomic_get_new_crtc_state(state,
> - new_plane_state->crtc);
> -
> - pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
> - r_pipe->sspp = NULL;
> -
> - if (!pipe->sspp)
> - return -EINVAL;
> -
> - pipe_hw_caps = pipe->sspp->cap;
> - sblk = pipe->sspp->cap->sblk;
> -
> - if (sblk->scaler_blk.len) {
> - min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
> - max_scale = MAX_DOWNSCALE_RATIO << 16;
> - } else {
> - min_scale = 1 << 16;
> - max_scale = 1 << 16;
> - }
> + min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
> + max_scale = MAX_DOWNSCALE_RATIO << 16;
>
> ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
> min_scale,
> @@ -844,11 +816,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> if (!new_plane_state->visible)
> return 0;
>
> - 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;
> -
> pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos;
> if (pstate->stage >= pdpu->catalog->caps->max_mixer_blendstages) {
> DPU_ERROR("> %d plane stages assigned\n",
> @@ -872,8 +839,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> return -E2BIG;
> }
>
> - fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
> -
> max_linewidth = pdpu->catalog->caps->max_linewidth;
>
> drm_rect_rotate(&pipe_cfg->src_rect,
> @@ -882,6 +847,83 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
>
> 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;
> + }
> +
> + *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));
> + }
> +
> + drm_rect_rotate_inv(&pipe_cfg->src_rect,
> + new_plane_state->fb->width, new_plane_state->fb->height,
> + new_plane_state->rotation);
> + if (r_pipe_cfg->src_rect.x1 != 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;
> +}
> +
> +static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
> + struct drm_atomic_state *state,
> + const struct drm_crtc_state *crtc_state)
> +{
> + struct drm_plane_state *new_plane_state =
> + 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;
> + 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;
> + uint32_t max_linewidth;
> + unsigned int rotation;
> + uint32_t supported_rotations;
> + const struct dpu_sspp_cfg *pipe_hw_caps;
> + const struct dpu_sspp_sub_blks *sblk;
> + int ret = 0;
> +
> + pipe_hw_caps = pipe->sspp->cap;
> + sblk = pipe->sspp->cap->sblk;
> +
> + /*
> + * We already have verified scaling against platform limitations.
> + * Now check if the SSPP supports scaling at all.
> + */
> + if (!sblk->scaler_blk.len &&
> + ((drm_rect_width(&new_plane_state->src) >> 16 !=
> + drm_rect_width(&new_plane_state->dst)) ||
> + (drm_rect_height(&new_plane_state->src) >> 16 !=
> + drm_rect_height(&new_plane_state->dst))))
> + return -ERANGE;
> +
> + 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;
> +
> + fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
> +
> + max_linewidth = pdpu->catalog->caps->max_linewidth;
> +
> + ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt,
> + &crtc_state->adjusted_mode);
> + if (ret)
> + return ret;
> +
> + if (r_pipe_cfg->src_rect.x1 != 0) {
> /*
> * In parallel multirect case only the half of the usual width
> * is supported for tiled formats. If we are here, we know that
> @@ -895,12 +937,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> return -E2BIG;
> }
>
> - 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;
> - }
> -
> 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) &&
> @@ -922,26 +958,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> 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;
> - }
> -
> - drm_rect_rotate_inv(&pipe_cfg->src_rect,
> - new_plane_state->fb->width, new_plane_state->fb->height,
> - new_plane_state->rotation);
> - if (r_pipe->sspp)
> - drm_rect_rotate_inv(&r_pipe_cfg->src_rect,
> - new_plane_state->fb->width, new_plane_state->fb->height,
> - new_plane_state->rotation);
> -
> - ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt, &crtc_state->adjusted_mode);
> - if (ret)
> - return ret;
> -
> - if (r_pipe->sspp) {
> ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, fmt,
> &crtc_state->adjusted_mode);
> if (ret)
> @@ -964,11 +980,45 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> }
>
> pstate->rotation = rotation;
> - pstate->needs_qos_remap = drm_atomic_crtc_needs_modeset(crtc_state);
>
> return 0;
> }
>
> +static int dpu_plane_atomic_check(struct drm_plane *plane,
> + struct drm_atomic_state *state)
> +{
> + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> + plane);
> + int ret = 0;
> + 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;
> + const struct drm_crtc_state *crtc_state = NULL;
> +
> + if (new_plane_state->crtc)
> + crtc_state = drm_atomic_get_new_crtc_state(state,
> + new_plane_state->crtc);
> +
> + if (pdpu->pipe != SSPP_NONE) {
This check was not present iirc, why did you have to add this?
RM will return the same SSPP unless freed. So why this additional check?
> + pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
> + r_pipe->sspp = NULL;
> + }
> +
> + if (!pipe->sspp)
> + return -EINVAL;
> +
> + ret = dpu_plane_atomic_check_nopipe(plane, new_plane_state, crtc_state);
> + if (ret)
> + return ret;
> +
> + if (!new_plane_state->visible)
> + return 0;
> +
> + return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
> +}
> +
> static void dpu_plane_flush_csc(struct dpu_plane *pdpu, struct dpu_sw_pipe *pipe)
> {
> const struct dpu_format *format =
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 06/13] drm/msm/dpu: split dpu_plane_atomic_check()
2024-06-05 23:19 ` Abhinav Kumar
@ 2024-06-05 23:32 ` Dmitry Baryshkov
2024-06-05 23:47 ` Abhinav Kumar
0 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-06-05 23:32 UTC (permalink / raw)
To: Abhinav Kumar
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On Thu, 6 Jun 2024 at 02:19, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>
>
>
> On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> > Split dpu_plane_atomic_check() function into two pieces:
> >
> > dpu_plane_atomic_check_nopipe() performing generic checks on the pstate,
> > without touching the associated pipe,
> >
> > and
> >
> > dpu_plane_atomic_check_pipes(), which takes into account used pipes.
> >
> > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > ---
> > drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 184 ++++++++++++++--------
> > 1 file changed, 117 insertions(+), 67 deletions(-)
> >
>
> One thing which seemed odd to me is even dpu_plane_atomic_check_nopipe()
> does use pipe_cfg even though its named "nopipe".
>
> Perhaps were you targetting a split of SW planes vs SSPP atomic_check?
>
> I tried applying this patch on top of msm-next to more closely review
> the split up but it does not apply. So, I will review this patch a
> little better after it is re-spun. But will proceed with remaining patches.
>
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > index 6360052523b5..187ac2767a2b 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > @@ -788,50 +788,22 @@ static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu,
> > #define MAX_UPSCALE_RATIO 20
> > #define MAX_DOWNSCALE_RATIO 4
> >
> > -static int dpu_plane_atomic_check(struct drm_plane *plane,
> > - struct drm_atomic_state *state)
> > +static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
> > + struct drm_plane_state *new_plane_state,
> > + const struct drm_crtc_state *crtc_state)
> > {
> > - struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> > - plane);
> > int ret = 0, min_scale, max_scale;
> > struct dpu_plane *pdpu = to_dpu_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_kms *dpu_kms = _dpu_plane_get_kms(plane);
> > - 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;
> > - uint32_t supported_rotations;
> > - const struct dpu_sspp_cfg *pipe_hw_caps;
> > - const struct dpu_sspp_sub_blks *sblk;
> >
> > - if (new_plane_state->crtc)
> > - crtc_state = drm_atomic_get_new_crtc_state(state,
> > - new_plane_state->crtc);
> > -
> > - pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
> > - r_pipe->sspp = NULL;
> > -
> > - if (!pipe->sspp)
> > - return -EINVAL;
> > -
> > - pipe_hw_caps = pipe->sspp->cap;
> > - sblk = pipe->sspp->cap->sblk;
> > -
> > - if (sblk->scaler_blk.len) {
> > - min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
> > - max_scale = MAX_DOWNSCALE_RATIO << 16;
> > - } else {
> > - min_scale = 1 << 16;
> > - max_scale = 1 << 16;
> > - }
> > + min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
> > + max_scale = MAX_DOWNSCALE_RATIO << 16;
> >
> > ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
> > min_scale,
> > @@ -844,11 +816,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> > if (!new_plane_state->visible)
> > return 0;
> >
> > - 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;
> > -
> > pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos;
> > if (pstate->stage >= pdpu->catalog->caps->max_mixer_blendstages) {
> > DPU_ERROR("> %d plane stages assigned\n",
> > @@ -872,8 +839,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> > return -E2BIG;
> > }
> >
> > - fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
> > -
> > max_linewidth = pdpu->catalog->caps->max_linewidth;
> >
> > drm_rect_rotate(&pipe_cfg->src_rect,
> > @@ -882,6 +847,83 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> >
> > 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;
> > + }
> > +
> > + *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));
> > + }
> > +
> > + drm_rect_rotate_inv(&pipe_cfg->src_rect,
> > + new_plane_state->fb->width, new_plane_state->fb->height,
> > + new_plane_state->rotation);
> > + if (r_pipe_cfg->src_rect.x1 != 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;
> > +}
> > +
> > +static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
> > + struct drm_atomic_state *state,
> > + const struct drm_crtc_state *crtc_state)
> > +{
> > + struct drm_plane_state *new_plane_state =
> > + 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;
> > + 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;
> > + uint32_t max_linewidth;
> > + unsigned int rotation;
> > + uint32_t supported_rotations;
> > + const struct dpu_sspp_cfg *pipe_hw_caps;
> > + const struct dpu_sspp_sub_blks *sblk;
> > + int ret = 0;
> > +
> > + pipe_hw_caps = pipe->sspp->cap;
> > + sblk = pipe->sspp->cap->sblk;
> > +
> > + /*
> > + * We already have verified scaling against platform limitations.
> > + * Now check if the SSPP supports scaling at all.
> > + */
> > + if (!sblk->scaler_blk.len &&
> > + ((drm_rect_width(&new_plane_state->src) >> 16 !=
> > + drm_rect_width(&new_plane_state->dst)) ||
> > + (drm_rect_height(&new_plane_state->src) >> 16 !=
> > + drm_rect_height(&new_plane_state->dst))))
> > + return -ERANGE;
> > +
> > + 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;
> > +
> > + fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
> > +
> > + max_linewidth = pdpu->catalog->caps->max_linewidth;
> > +
> > + ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt,
> > + &crtc_state->adjusted_mode);
> > + if (ret)
> > + return ret;
> > +
> > + if (r_pipe_cfg->src_rect.x1 != 0) {
> > /*
> > * In parallel multirect case only the half of the usual width
> > * is supported for tiled formats. If we are here, we know that
> > @@ -895,12 +937,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> > return -E2BIG;
> > }
> >
> > - 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;
> > - }
> > -
> > 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) &&
> > @@ -922,26 +958,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> > 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;
> > - }
> > -
> > - drm_rect_rotate_inv(&pipe_cfg->src_rect,
> > - new_plane_state->fb->width, new_plane_state->fb->height,
> > - new_plane_state->rotation);
> > - if (r_pipe->sspp)
> > - drm_rect_rotate_inv(&r_pipe_cfg->src_rect,
> > - new_plane_state->fb->width, new_plane_state->fb->height,
> > - new_plane_state->rotation);
> > -
> > - ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt, &crtc_state->adjusted_mode);
> > - if (ret)
> > - return ret;
> > -
> > - if (r_pipe->sspp) {
> > ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, fmt,
> > &crtc_state->adjusted_mode);
> > if (ret)
> > @@ -964,11 +980,45 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> > }
> >
> > pstate->rotation = rotation;
> > - pstate->needs_qos_remap = drm_atomic_crtc_needs_modeset(crtc_state);
> >
> > return 0;
> > }
> >
> > +static int dpu_plane_atomic_check(struct drm_plane *plane,
> > + struct drm_atomic_state *state)
> > +{
> > + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> > + plane);
> > + int ret = 0;
> > + 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;
> > + const struct drm_crtc_state *crtc_state = NULL;
> > +
> > + if (new_plane_state->crtc)
> > + crtc_state = drm_atomic_get_new_crtc_state(state,
> > + new_plane_state->crtc);
> > +
> > + if (pdpu->pipe != SSPP_NONE) {
>
> This check was not present iirc, why did you have to add this?
> RM will return the same SSPP unless freed. So why this additional check?
If pdpu->pipe is not SSPP_NONE, then virtual planes are disabled and
there is a fixed 1:1 relationship between planes and SSPP blocks.
>
> > + pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
> > + r_pipe->sspp = NULL;
> > + }
> > +
> > + if (!pipe->sspp)
> > + return -EINVAL;
> > +
> > + ret = dpu_plane_atomic_check_nopipe(plane, new_plane_state, crtc_state);
> > + if (ret)
> > + return ret;
> > +
> > + if (!new_plane_state->visible)
> > + return 0;
> > +
> > + return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
> > +}
> > +
> > static void dpu_plane_flush_csc(struct dpu_plane *pdpu, struct dpu_sw_pipe *pipe)
> > {
> > const struct dpu_format *format =
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 06/13] drm/msm/dpu: split dpu_plane_atomic_check()
2024-06-05 23:32 ` Dmitry Baryshkov
@ 2024-06-05 23:47 ` Abhinav Kumar
2024-06-06 8:53 ` Dmitry Baryshkov
0 siblings, 1 reply; 50+ messages in thread
From: Abhinav Kumar @ 2024-06-05 23:47 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On 6/5/2024 4:32 PM, Dmitry Baryshkov wrote:
> On Thu, 6 Jun 2024 at 02:19, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>>
>>
>>
>> On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
>>> Split dpu_plane_atomic_check() function into two pieces:
>>>
>>> dpu_plane_atomic_check_nopipe() performing generic checks on the pstate,
>>> without touching the associated pipe,
>>>
>>> and
>>>
>>> dpu_plane_atomic_check_pipes(), which takes into account used pipes.
>>>
>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>> ---
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 184 ++++++++++++++--------
>>> 1 file changed, 117 insertions(+), 67 deletions(-)
>>>
>>
>> One thing which seemed odd to me is even dpu_plane_atomic_check_nopipe()
>> does use pipe_cfg even though its named "nopipe".
>>
>> Perhaps were you targetting a split of SW planes vs SSPP atomic_check?
>>
>> I tried applying this patch on top of msm-next to more closely review
>> the split up but it does not apply. So, I will review this patch a
>> little better after it is re-spun. But will proceed with remaining patches.
>>
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>> index 6360052523b5..187ac2767a2b 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>> @@ -788,50 +788,22 @@ static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu,
>>> #define MAX_UPSCALE_RATIO 20
>>> #define MAX_DOWNSCALE_RATIO 4
>>>
>>> -static int dpu_plane_atomic_check(struct drm_plane *plane,
>>> - struct drm_atomic_state *state)
>>> +static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
>>> + struct drm_plane_state *new_plane_state,
>>> + const struct drm_crtc_state *crtc_state)
>>> {
>>> - struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
>>> - plane);
>>> int ret = 0, min_scale, max_scale;
>>> struct dpu_plane *pdpu = to_dpu_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_kms *dpu_kms = _dpu_plane_get_kms(plane);
>>> - 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;
>>> - uint32_t supported_rotations;
>>> - const struct dpu_sspp_cfg *pipe_hw_caps;
>>> - const struct dpu_sspp_sub_blks *sblk;
>>>
>>> - if (new_plane_state->crtc)
>>> - crtc_state = drm_atomic_get_new_crtc_state(state,
>>> - new_plane_state->crtc);
>>> -
>>> - pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
>>> - r_pipe->sspp = NULL;
>>> -
>>> - if (!pipe->sspp)
>>> - return -EINVAL;
>>> -
>>> - pipe_hw_caps = pipe->sspp->cap;
>>> - sblk = pipe->sspp->cap->sblk;
>>> -
>>> - if (sblk->scaler_blk.len) {
>>> - min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
>>> - max_scale = MAX_DOWNSCALE_RATIO << 16;
>>> - } else {
>>> - min_scale = 1 << 16;
>>> - max_scale = 1 << 16;
>>> - }
>>> + min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
>>> + max_scale = MAX_DOWNSCALE_RATIO << 16;
>>>
>>> ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
>>> min_scale,
>>> @@ -844,11 +816,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
>>> if (!new_plane_state->visible)
>>> return 0;
>>>
>>> - 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;
>>> -
>>> pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos;
>>> if (pstate->stage >= pdpu->catalog->caps->max_mixer_blendstages) {
>>> DPU_ERROR("> %d plane stages assigned\n",
>>> @@ -872,8 +839,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
>>> return -E2BIG;
>>> }
>>>
>>> - fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
>>> -
>>> max_linewidth = pdpu->catalog->caps->max_linewidth;
>>>
>>> drm_rect_rotate(&pipe_cfg->src_rect,
>>> @@ -882,6 +847,83 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
>>>
>>> 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;
>>> + }
>>> +
>>> + *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));
>>> + }
>>> +
>>> + drm_rect_rotate_inv(&pipe_cfg->src_rect,
>>> + new_plane_state->fb->width, new_plane_state->fb->height,
>>> + new_plane_state->rotation);
>>> + if (r_pipe_cfg->src_rect.x1 != 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;
>>> +}
>>> +
>>> +static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
>>> + struct drm_atomic_state *state,
>>> + const struct drm_crtc_state *crtc_state)
>>> +{
>>> + struct drm_plane_state *new_plane_state =
>>> + 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;
>>> + 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;
>>> + uint32_t max_linewidth;
>>> + unsigned int rotation;
>>> + uint32_t supported_rotations;
>>> + const struct dpu_sspp_cfg *pipe_hw_caps;
>>> + const struct dpu_sspp_sub_blks *sblk;
>>> + int ret = 0;
>>> +
>>> + pipe_hw_caps = pipe->sspp->cap;
>>> + sblk = pipe->sspp->cap->sblk;
>>> +
>>> + /*
>>> + * We already have verified scaling against platform limitations.
>>> + * Now check if the SSPP supports scaling at all.
>>> + */
>>> + if (!sblk->scaler_blk.len &&
>>> + ((drm_rect_width(&new_plane_state->src) >> 16 !=
>>> + drm_rect_width(&new_plane_state->dst)) ||
>>> + (drm_rect_height(&new_plane_state->src) >> 16 !=
>>> + drm_rect_height(&new_plane_state->dst))))
>>> + return -ERANGE;
>>> +
>>> + 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;
>>> +
>>> + fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
>>> +
>>> + max_linewidth = pdpu->catalog->caps->max_linewidth;
>>> +
>>> + ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt,
>>> + &crtc_state->adjusted_mode);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + if (r_pipe_cfg->src_rect.x1 != 0) {
>>> /*
>>> * In parallel multirect case only the half of the usual width
>>> * is supported for tiled formats. If we are here, we know that
>>> @@ -895,12 +937,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
>>> return -E2BIG;
>>> }
>>>
>>> - 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;
>>> - }
>>> -
>>> 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) &&
>>> @@ -922,26 +958,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
>>> 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;
>>> - }
>>> -
>>> - drm_rect_rotate_inv(&pipe_cfg->src_rect,
>>> - new_plane_state->fb->width, new_plane_state->fb->height,
>>> - new_plane_state->rotation);
>>> - if (r_pipe->sspp)
>>> - drm_rect_rotate_inv(&r_pipe_cfg->src_rect,
>>> - new_plane_state->fb->width, new_plane_state->fb->height,
>>> - new_plane_state->rotation);
>>> -
>>> - ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt, &crtc_state->adjusted_mode);
>>> - if (ret)
>>> - return ret;
>>> -
>>> - if (r_pipe->sspp) {
>>> ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, fmt,
>>> &crtc_state->adjusted_mode);
>>> if (ret)
>>> @@ -964,11 +980,45 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
>>> }
>>>
>>> pstate->rotation = rotation;
>>> - pstate->needs_qos_remap = drm_atomic_crtc_needs_modeset(crtc_state);
>>>
>>> return 0;
>>> }
>>>
>>> +static int dpu_plane_atomic_check(struct drm_plane *plane,
>>> + struct drm_atomic_state *state)
>>> +{
>>> + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
>>> + plane);
>>> + int ret = 0;
>>> + 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;
>>> + const struct drm_crtc_state *crtc_state = NULL;
>>> +
>>> + if (new_plane_state->crtc)
>>> + crtc_state = drm_atomic_get_new_crtc_state(state,
>>> + new_plane_state->crtc);
>>> +
>>> + if (pdpu->pipe != SSPP_NONE) {
>>
>> This check was not present iirc, why did you have to add this?
>> RM will return the same SSPP unless freed. So why this additional check?
>
> If pdpu->pipe is not SSPP_NONE, then virtual planes are disabled and
> there is a fixed 1:1 relationship between planes and SSPP blocks.
>
True, pdpu->pipe is currently assigned in dpu_plane_init(), so we will
always be hitting this condition.
Perhaps the patches later on are changing that, so shouldnt this part
come along with those?
>>
>>> + pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
>>> + r_pipe->sspp = NULL;
>>> + }
>>> +
>>> + if (!pipe->sspp)
>>> + return -EINVAL;
>>> +
>>> + ret = dpu_plane_atomic_check_nopipe(plane, new_plane_state, crtc_state);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + if (!new_plane_state->visible)
>>> + return 0;
>>> +
>>> + return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
>>> +}
>>> +
>>> static void dpu_plane_flush_csc(struct dpu_plane *pdpu, struct dpu_sw_pipe *pipe)
>>> {
>>> const struct dpu_format *format =
>
>
>
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 06/13] drm/msm/dpu: split dpu_plane_atomic_check()
2024-06-05 23:47 ` Abhinav Kumar
@ 2024-06-06 8:53 ` Dmitry Baryshkov
2024-06-06 8:54 ` Dmitry Baryshkov
0 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-06-06 8:53 UTC (permalink / raw)
To: Abhinav Kumar
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On Thu, 6 Jun 2024 at 02:47, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>
>
>
> On 6/5/2024 4:32 PM, Dmitry Baryshkov wrote:
> > On Thu, 6 Jun 2024 at 02:19, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
> >>
> >>
> >>
> >> On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> >>> Split dpu_plane_atomic_check() function into two pieces:
> >>>
> >>> dpu_plane_atomic_check_nopipe() performing generic checks on the pstate,
> >>> without touching the associated pipe,
> >>>
> >>> and
> >>>
> >>> dpu_plane_atomic_check_pipes(), which takes into account used pipes.
> >>>
> >>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> >>> ---
> >>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 184 ++++++++++++++--------
> >>> 1 file changed, 117 insertions(+), 67 deletions(-)
> >>>
> >>
> >> One thing which seemed odd to me is even dpu_plane_atomic_check_nopipe()
> >> does use pipe_cfg even though its named "nopipe".
> >>
> >> Perhaps were you targetting a split of SW planes vs SSPP atomic_check?
> >>
> >> I tried applying this patch on top of msm-next to more closely review
> >> the split up but it does not apply. So, I will review this patch a
> >> little better after it is re-spun. But will proceed with remaining patches.
> >>
> >>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> >>> index 6360052523b5..187ac2767a2b 100644
> >>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> >>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> >>> @@ -788,50 +788,22 @@ static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu,
> >>> #define MAX_UPSCALE_RATIO 20
> >>> #define MAX_DOWNSCALE_RATIO 4
> >>>
> >>> -static int dpu_plane_atomic_check(struct drm_plane *plane,
> >>> - struct drm_atomic_state *state)
> >>> +static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
> >>> + struct drm_plane_state *new_plane_state,
> >>> + const struct drm_crtc_state *crtc_state)
> >>> {
> >>> - struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> >>> - plane);
> >>> int ret = 0, min_scale, max_scale;
> >>> struct dpu_plane *pdpu = to_dpu_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_kms *dpu_kms = _dpu_plane_get_kms(plane);
> >>> - 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;
> >>> - uint32_t supported_rotations;
> >>> - const struct dpu_sspp_cfg *pipe_hw_caps;
> >>> - const struct dpu_sspp_sub_blks *sblk;
> >>>
> >>> - if (new_plane_state->crtc)
> >>> - crtc_state = drm_atomic_get_new_crtc_state(state,
> >>> - new_plane_state->crtc);
> >>> -
> >>> - pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
> >>> - r_pipe->sspp = NULL;
> >>> -
> >>> - if (!pipe->sspp)
> >>> - return -EINVAL;
> >>> -
> >>> - pipe_hw_caps = pipe->sspp->cap;
> >>> - sblk = pipe->sspp->cap->sblk;
> >>> -
> >>> - if (sblk->scaler_blk.len) {
> >>> - min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
> >>> - max_scale = MAX_DOWNSCALE_RATIO << 16;
> >>> - } else {
> >>> - min_scale = 1 << 16;
> >>> - max_scale = 1 << 16;
> >>> - }
> >>> + min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
> >>> + max_scale = MAX_DOWNSCALE_RATIO << 16;
> >>>
> >>> ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
> >>> min_scale,
> >>> @@ -844,11 +816,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> >>> if (!new_plane_state->visible)
> >>> return 0;
> >>>
> >>> - 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;
> >>> -
> >>> pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos;
> >>> if (pstate->stage >= pdpu->catalog->caps->max_mixer_blendstages) {
> >>> DPU_ERROR("> %d plane stages assigned\n",
> >>> @@ -872,8 +839,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> >>> return -E2BIG;
> >>> }
> >>>
> >>> - fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
> >>> -
> >>> max_linewidth = pdpu->catalog->caps->max_linewidth;
> >>>
> >>> drm_rect_rotate(&pipe_cfg->src_rect,
> >>> @@ -882,6 +847,83 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> >>>
> >>> 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;
> >>> + }
> >>> +
> >>> + *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));
> >>> + }
> >>> +
> >>> + drm_rect_rotate_inv(&pipe_cfg->src_rect,
> >>> + new_plane_state->fb->width, new_plane_state->fb->height,
> >>> + new_plane_state->rotation);
> >>> + if (r_pipe_cfg->src_rect.x1 != 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;
> >>> +}
> >>> +
> >>> +static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
> >>> + struct drm_atomic_state *state,
> >>> + const struct drm_crtc_state *crtc_state)
> >>> +{
> >>> + struct drm_plane_state *new_plane_state =
> >>> + 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;
> >>> + 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;
> >>> + uint32_t max_linewidth;
> >>> + unsigned int rotation;
> >>> + uint32_t supported_rotations;
> >>> + const struct dpu_sspp_cfg *pipe_hw_caps;
> >>> + const struct dpu_sspp_sub_blks *sblk;
> >>> + int ret = 0;
> >>> +
> >>> + pipe_hw_caps = pipe->sspp->cap;
> >>> + sblk = pipe->sspp->cap->sblk;
> >>> +
> >>> + /*
> >>> + * We already have verified scaling against platform limitations.
> >>> + * Now check if the SSPP supports scaling at all.
> >>> + */
> >>> + if (!sblk->scaler_blk.len &&
> >>> + ((drm_rect_width(&new_plane_state->src) >> 16 !=
> >>> + drm_rect_width(&new_plane_state->dst)) ||
> >>> + (drm_rect_height(&new_plane_state->src) >> 16 !=
> >>> + drm_rect_height(&new_plane_state->dst))))
> >>> + return -ERANGE;
> >>> +
> >>> + 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;
> >>> +
> >>> + fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
> >>> +
> >>> + max_linewidth = pdpu->catalog->caps->max_linewidth;
> >>> +
> >>> + ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt,
> >>> + &crtc_state->adjusted_mode);
> >>> + if (ret)
> >>> + return ret;
> >>> +
> >>> + if (r_pipe_cfg->src_rect.x1 != 0) {
> >>> /*
> >>> * In parallel multirect case only the half of the usual width
> >>> * is supported for tiled formats. If we are here, we know that
> >>> @@ -895,12 +937,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> >>> return -E2BIG;
> >>> }
> >>>
> >>> - 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;
> >>> - }
> >>> -
> >>> 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) &&
> >>> @@ -922,26 +958,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> >>> 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;
> >>> - }
> >>> -
> >>> - drm_rect_rotate_inv(&pipe_cfg->src_rect,
> >>> - new_plane_state->fb->width, new_plane_state->fb->height,
> >>> - new_plane_state->rotation);
> >>> - if (r_pipe->sspp)
> >>> - drm_rect_rotate_inv(&r_pipe_cfg->src_rect,
> >>> - new_plane_state->fb->width, new_plane_state->fb->height,
> >>> - new_plane_state->rotation);
> >>> -
> >>> - ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt, &crtc_state->adjusted_mode);
> >>> - if (ret)
> >>> - return ret;
> >>> -
> >>> - if (r_pipe->sspp) {
> >>> ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, fmt,
> >>> &crtc_state->adjusted_mode);
> >>> if (ret)
> >>> @@ -964,11 +980,45 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> >>> }
> >>>
> >>> pstate->rotation = rotation;
> >>> - pstate->needs_qos_remap = drm_atomic_crtc_needs_modeset(crtc_state);
> >>>
> >>> return 0;
> >>> }
> >>>
> >>> +static int dpu_plane_atomic_check(struct drm_plane *plane,
> >>> + struct drm_atomic_state *state)
> >>> +{
> >>> + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> >>> + plane);
> >>> + int ret = 0;
> >>> + 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;
> >>> + const struct drm_crtc_state *crtc_state = NULL;
> >>> +
> >>> + if (new_plane_state->crtc)
> >>> + crtc_state = drm_atomic_get_new_crtc_state(state,
> >>> + new_plane_state->crtc);
> >>> +
> >>> + if (pdpu->pipe != SSPP_NONE) {
> >>
> >> This check was not present iirc, why did you have to add this?
> >> RM will return the same SSPP unless freed. So why this additional check?
> >
> > If pdpu->pipe is not SSPP_NONE, then virtual planes are disabled and
> > there is a fixed 1:1 relationship between planes and SSPP blocks.
> >
>
> True, pdpu->pipe is currently assigned in dpu_plane_init(), so we will
> always be hitting this condition.
>
> Perhaps the patches later on are changing that, so shouldnt this part
> come along with those?
Ack, I'll move it to patch 5.
>
> >>
> >>> + pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
> >>> + r_pipe->sspp = NULL;
> >>> + }
> >>> +
> >>> + if (!pipe->sspp)
> >>> + return -EINVAL;
> >>> +
> >>> + ret = dpu_plane_atomic_check_nopipe(plane, new_plane_state, crtc_state);
> >>> + if (ret)
> >>> + return ret;
> >>> +
> >>> + if (!new_plane_state->visible)
> >>> + return 0;
> >>> +
> >>> + return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
> >>> +}
> >>> +
> >>> static void dpu_plane_flush_csc(struct dpu_plane *pdpu, struct dpu_sw_pipe *pipe)
> >>> {
> >>> const struct dpu_format *format =
> >
> >
> >
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 06/13] drm/msm/dpu: split dpu_plane_atomic_check()
2024-06-06 8:53 ` Dmitry Baryshkov
@ 2024-06-06 8:54 ` Dmitry Baryshkov
0 siblings, 0 replies; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-06-06 8:54 UTC (permalink / raw)
To: Abhinav Kumar
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On Thu, 6 Jun 2024 at 11:53, Dmitry Baryshkov
<dmitry.baryshkov@linaro.org> wrote:
>
> On Thu, 6 Jun 2024 at 02:47, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
> >
> >
> >
> > On 6/5/2024 4:32 PM, Dmitry Baryshkov wrote:
> > > On Thu, 6 Jun 2024 at 02:19, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
> > >>
> > >>
> > >>
> > >> On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> > >>> Split dpu_plane_atomic_check() function into two pieces:
> > >>>
> > >>> dpu_plane_atomic_check_nopipe() performing generic checks on the pstate,
> > >>> without touching the associated pipe,
> > >>>
> > >>> and
> > >>>
> > >>> dpu_plane_atomic_check_pipes(), which takes into account used pipes.
> > >>>
> > >>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > >>> ---
> > >>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 184 ++++++++++++++--------
> > >>> 1 file changed, 117 insertions(+), 67 deletions(-)
> > >>>
> > >>> + if (new_plane_state->crtc)
> > >>> + crtc_state = drm_atomic_get_new_crtc_state(state,
> > >>> + new_plane_state->crtc);
> > >>> +
> > >>> + if (pdpu->pipe != SSPP_NONE) {
> > >>
> > >> This check was not present iirc, why did you have to add this?
> > >> RM will return the same SSPP unless freed. So why this additional check?
> > >
> > > If pdpu->pipe is not SSPP_NONE, then virtual planes are disabled and
> > > there is a fixed 1:1 relationship between planes and SSPP blocks.
> > >
> >
> > True, pdpu->pipe is currently assigned in dpu_plane_init(), so we will
> > always be hitting this condition.
> >
> > Perhaps the patches later on are changing that, so shouldnt this part
> > come along with those?
>
> Ack, I'll move it to patch 5.
Patch 8, of course.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v4 07/13] drm/msm/dpu: move rot90 checking to dpu_plane_atomic_check_pipe()
2024-03-14 0:02 [PATCH v4 00/13] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
` (5 preceding siblings ...)
2024-03-14 0:02 ` [PATCH v4 06/13] drm/msm/dpu: split dpu_plane_atomic_check() Dmitry Baryshkov
@ 2024-03-14 0:02 ` Dmitry Baryshkov
2024-06-05 23:34 ` Abhinav Kumar
2024-03-14 0:02 ` [PATCH v4 08/13] drm/msm/dpu: add support for virtual planes Dmitry Baryshkov
` (6 subsequent siblings)
13 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-03-14 0:02 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Abhinav Kumar, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
Move a call to dpu_plane_check_inline_rotation() to the
dpu_plane_atomic_check_pipe() function, so that the rot90 constraints
are checked for both pipes. Also move rotation field from struct
dpu_plane_state to struct dpu_sw_pipe_cfg.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h | 2 +
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 55 +++++++++++----------
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 2 -
3 files changed, 31 insertions(+), 28 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h
index b7dc52312c39..a774404b42b5 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h
@@ -142,10 +142,12 @@ struct dpu_hw_pixel_ext {
* @src_rect: src ROI, caller takes into account the different operations
* such as decimation, flip etc to program this field
* @dest_rect: destination ROI.
+ * @rotation: simplified drm rotation hint
*/
struct dpu_sw_pipe_cfg {
struct drm_rect src_rect;
struct drm_rect dst_rect;
+ unsigned int rotation;
};
/**
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index 187ac2767a2b..a41ffa2d774b 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -527,8 +527,7 @@ static const struct dpu_csc_cfg *_dpu_plane_get_csc(struct dpu_sw_pipe *pipe,
static void _dpu_plane_setup_scaler(struct dpu_sw_pipe *pipe,
const struct dpu_format *fmt, bool color_fill,
- struct dpu_sw_pipe_cfg *pipe_cfg,
- unsigned int rotation)
+ struct dpu_sw_pipe_cfg *pipe_cfg)
{
struct dpu_hw_sspp *pipe_hw = pipe->sspp;
const struct drm_format_info *info = drm_format_info(fmt->base.pixel_format);
@@ -551,7 +550,7 @@ static void _dpu_plane_setup_scaler(struct dpu_sw_pipe *pipe,
dst_height,
&scaler3_cfg, fmt,
info->hsub, info->vsub,
- rotation);
+ pipe_cfg->rotation);
/* configure pixel extension based on scalar config */
_dpu_plane_setup_pixel_ext(&scaler3_cfg, &pixel_ext,
@@ -603,7 +602,7 @@ static void _dpu_plane_color_fill_pipe(struct dpu_plane_state *pstate,
if (pipe->sspp->ops.setup_rects)
pipe->sspp->ops.setup_rects(pipe, &pipe_cfg);
- _dpu_plane_setup_scaler(pipe, fmt, true, &pipe_cfg, pstate->rotation);
+ _dpu_plane_setup_scaler(pipe, fmt, true, &pipe_cfg);
}
/**
@@ -703,12 +702,17 @@ static void dpu_plane_cleanup_fb(struct drm_plane *plane,
}
static int dpu_plane_check_inline_rotation(struct dpu_plane *pdpu,
- const struct dpu_sspp_sub_blks *sblk,
- struct drm_rect src, const struct dpu_format *fmt)
+ struct dpu_sw_pipe *pipe,
+ struct drm_rect src,
+ const struct dpu_format *fmt)
{
+ const struct dpu_sspp_sub_blks *sblk = pipe->sspp->cap->sblk;
size_t num_formats;
const u32 *supported_formats;
+ if (!test_bit(DPU_SSPP_INLINE_ROTATION, &pipe->sspp->cap->features))
+ return -EINVAL;
+
if (!sblk->rotation_cfg) {
DPU_ERROR("invalid rotation cfg\n");
return -EINVAL;
@@ -738,6 +742,7 @@ static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu,
{
uint32_t min_src_size;
struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);
+ int ret;
min_src_size = DPU_FORMAT_IS_YUV(fmt) ? 2 : 1;
@@ -776,6 +781,12 @@ static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu,
return -EINVAL;
}
+ if (pipe_cfg->rotation & DRM_MODE_ROTATE_90) {
+ ret = dpu_plane_check_inline_rotation(pdpu, pipe, pipe_cfg->src_rect, fmt);
+ if (ret)
+ return ret;
+ }
+
/* max clk check */
if (_dpu_plane_calc_clk(mode, pipe_cfg) > kms->perf.max_core_clk_rate) {
DPU_DEBUG_PLANE(pdpu, "plane exceeds max mdp core clk limits\n");
@@ -889,7 +900,6 @@ static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg;
struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg;
uint32_t max_linewidth;
- unsigned int rotation;
uint32_t supported_rotations;
const struct dpu_sspp_cfg *pipe_hw_caps;
const struct dpu_sspp_sub_blks *sblk;
@@ -918,6 +928,15 @@ static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
max_linewidth = pdpu->catalog->caps->max_linewidth;
+ supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0;
+
+ if (pipe_hw_caps->features & BIT(DPU_SSPP_INLINE_ROTATION))
+ supported_rotations |= DRM_MODE_ROTATE_90;
+
+ pipe_cfg->rotation = drm_rotation_simplify(new_plane_state->rotation,
+ supported_rotations);
+ r_pipe_cfg->rotation = pipe_cfg->rotation;
+
ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt,
&crtc_state->adjusted_mode);
if (ret)
@@ -941,6 +960,7 @@ static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
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)) ||
+ pipe_cfg->rotation & DRM_MODE_ROTATE_90 ||
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);
@@ -964,23 +984,6 @@ static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
return ret;
}
- supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0;
-
- if (pipe_hw_caps->features & BIT(DPU_SSPP_INLINE_ROTATION))
- supported_rotations |= DRM_MODE_ROTATE_90;
-
- rotation = drm_rotation_simplify(new_plane_state->rotation,
- supported_rotations);
-
- if ((pipe_hw_caps->features & BIT(DPU_SSPP_INLINE_ROTATION)) &&
- (rotation & DRM_MODE_ROTATE_90)) {
- ret = dpu_plane_check_inline_rotation(pdpu, sblk, pipe_cfg->src_rect, fmt);
- if (ret)
- return ret;
- }
-
- pstate->rotation = rotation;
-
return 0;
}
@@ -1120,14 +1123,14 @@ static void dpu_plane_sspp_update_pipe(struct drm_plane *plane,
pipe_cfg);
}
- _dpu_plane_setup_scaler(pipe, fmt, false, pipe_cfg, pstate->rotation);
+ _dpu_plane_setup_scaler(pipe, fmt, false, pipe_cfg);
if (pipe->sspp->ops.setup_multirect)
pipe->sspp->ops.setup_multirect(
pipe);
if (pipe->sspp->ops.setup_format) {
- unsigned int rotation = pstate->rotation;
+ unsigned int rotation = pipe_cfg->rotation;
src_flags = 0x0;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
index abd6b21a049b..a3ae45dc95d0 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
@@ -30,7 +30,6 @@
* @plane_fetch_bw: calculated BW per plane
* @plane_clk: calculated clk per plane
* @needs_dirtyfb: whether attached CRTC needs pixel data explicitly flushed
- * @rotation: simplified drm rotation hint
*/
struct dpu_plane_state {
struct drm_plane_state base;
@@ -47,7 +46,6 @@ struct dpu_plane_state {
u64 plane_clk;
bool needs_dirtyfb;
- unsigned int rotation;
};
#define to_dpu_plane_state(x) \
--
2.39.2
^ permalink raw reply related [flat|nested] 50+ messages in thread* Re: [PATCH v4 07/13] drm/msm/dpu: move rot90 checking to dpu_plane_atomic_check_pipe()
2024-03-14 0:02 ` [PATCH v4 07/13] drm/msm/dpu: move rot90 checking to dpu_plane_atomic_check_pipe() Dmitry Baryshkov
@ 2024-06-05 23:34 ` Abhinav Kumar
0 siblings, 0 replies; 50+ messages in thread
From: Abhinav Kumar @ 2024-06-05 23:34 UTC (permalink / raw)
To: Dmitry Baryshkov, Rob Clark, Sean Paul, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> Move a call to dpu_plane_check_inline_rotation() to the
> dpu_plane_atomic_check_pipe() function, so that the rot90 constraints
> are checked for both pipes. Also move rotation field from struct
> dpu_plane_state to struct dpu_sw_pipe_cfg.
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h | 2 +
> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 55 +++++++++++----------
> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 2 -
> 3 files changed, 31 insertions(+), 28 deletions(-)
>
From the first glance, no major comments, I will give my R-b on this
once its re-spun on msm-next.
^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v4 08/13] drm/msm/dpu: add support for virtual planes
2024-03-14 0:02 [PATCH v4 00/13] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
` (6 preceding siblings ...)
2024-03-14 0:02 ` [PATCH v4 07/13] drm/msm/dpu: move rot90 checking to dpu_plane_atomic_check_pipe() Dmitry Baryshkov
@ 2024-03-14 0:02 ` Dmitry Baryshkov
2024-03-14 8:04 ` [v4,08/13] " Sui Jingfeng
2024-06-06 22:21 ` [PATCH v4 08/13] " Abhinav Kumar
2024-03-14 0:02 ` [PATCH v4 09/13] drm/msm/dpu: allow using two SSPP blocks for a single plane Dmitry Baryshkov
` (5 subsequent siblings)
13 siblings, 2 replies; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-03-14 0:02 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Abhinav Kumar, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
Only several SSPP blocks support such features as YUV output or scaling,
thus different DRM planes have different features. Properly utilizing
all planes requires the attention of the compositor, who should
prefer simpler planes to YUV-supporting ones. Otherwise it is very easy
to end up in a situation when all featureful planes are already
allocated for simple windows, leaving no spare plane for YUV playback.
To solve this problem make all planes virtual. Each plane is registered
as if it supports all possible features, but then at the runtime during
the atomic_check phase the driver selects backing SSPP block for each
plane.
Note, this does not provide support for using two different SSPP blocks
for a single plane or using two rectangles of an SSPP to drive two
planes. Each plane still gets its own SSPP and can utilize either a solo
rectangle or both multirect rectangles depending on the resolution.
Note #2: By default support for virtual planes is turned off and the
driver still uses old code path with preallocated SSPP block for each
plane. To enable virtual planes, pass 'msm.dpu_use_virtual_planes=1'
kernel parameter.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 50 +++++
drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 10 +-
drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 4 +
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 230 +++++++++++++++++++---
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 19 ++
drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 77 ++++++++
drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 28 +++
7 files changed, 390 insertions(+), 28 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 88c2e51ab166..794c5643584f 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -1168,6 +1168,49 @@ static bool dpu_crtc_needs_dirtyfb(struct drm_crtc_state *cstate)
return false;
}
+static int dpu_crtc_reassign_planes(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
+{
+ int total_planes = crtc->dev->mode_config.num_total_plane;
+ struct drm_atomic_state *state = crtc_state->state;
+ struct dpu_global_state *global_state;
+ struct drm_plane_state **states;
+ struct drm_plane *plane;
+ int ret;
+
+ global_state = dpu_kms_get_global_state(crtc_state->state);
+ if (IS_ERR(global_state))
+ return PTR_ERR(global_state);
+
+ dpu_rm_release_all_sspp(global_state, crtc);
+
+ if (!crtc_state->enable)
+ return 0;
+
+ states = kcalloc(total_planes, sizeof(*states), GFP_KERNEL);
+ if (!states)
+ return -ENOMEM;
+
+ drm_atomic_crtc_state_for_each_plane(plane, crtc_state) {
+ struct drm_plane_state *plane_state =
+ drm_atomic_get_plane_state(state, plane);
+
+ if (IS_ERR(plane_state)) {
+ ret = PTR_ERR(plane_state);
+ goto done;
+ }
+
+ states[plane_state->normalized_zpos] = plane_state;
+ }
+
+ ret = dpu_assign_plane_resources(global_state, state, crtc, states, total_planes);
+
+done:
+ kfree(states);
+ return ret;
+
+ return 0;
+}
+
static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
struct drm_atomic_state *state)
{
@@ -1183,6 +1226,13 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
bool needs_dirtyfb = dpu_crtc_needs_dirtyfb(crtc_state);
+ if (dpu_use_virtual_planes &&
+ (crtc_state->planes_changed || crtc_state->zpos_changed)) {
+ rc = dpu_crtc_reassign_planes(crtc, crtc_state);
+ if (rc < 0)
+ return rc;
+ }
+
if (!crtc_state->enable || !drm_atomic_crtc_effectively_active(crtc_state)) {
DRM_DEBUG_ATOMIC("crtc%d -> enable %d, active %d, skip atomic_check\n",
crtc->base.id, crtc_state->enable,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 9a1fe6868979..becdd98f3c40 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -51,6 +51,9 @@
#define DPU_DEBUGFS_DIR "msm_dpu"
#define DPU_DEBUGFS_HWMASKNAME "hw_log_mask"
+bool dpu_use_virtual_planes = false;
+module_param(dpu_use_virtual_planes, bool, 0);
+
static int dpu_kms_hw_init(struct msm_kms *kms);
static void _dpu_kms_mmu_destroy(struct dpu_kms *dpu_kms);
@@ -770,8 +773,11 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms)
type, catalog->sspp[i].features,
catalog->sspp[i].features & BIT(DPU_SSPP_CURSOR));
- plane = dpu_plane_init(dev, catalog->sspp[i].id, type,
- (1UL << max_crtc_count) - 1);
+ if (dpu_use_virtual_planes)
+ plane = dpu_plane_init_virtual(dev, type, (1UL << max_crtc_count) - 1);
+ else
+ plane = dpu_plane_init(dev, catalog->sspp[i].id, type,
+ (1UL << max_crtc_count) - 1);
if (IS_ERR(plane)) {
DPU_ERROR("dpu_plane_init failed\n");
ret = PTR_ERR(plane);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
index e2adc937ea63..195257660057 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
@@ -64,6 +64,8 @@
#define ktime_compare_safe(A, B) \
ktime_compare(ktime_sub((A), (B)), ktime_set(0, 0))
+extern bool dpu_use_virtual_planes;
+
struct dpu_kms {
struct msm_kms base;
struct drm_device *dev;
@@ -138,6 +140,8 @@ struct dpu_global_state {
uint32_t dspp_to_enc_id[DSPP_MAX - DSPP_0];
uint32_t dsc_to_enc_id[DSC_MAX - DSC_0];
uint32_t cdm_to_enc_id;
+
+ uint32_t sspp_to_crtc_id[SSPP_MAX - SSPP_NONE];
};
struct dpu_global_state
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index a41ffa2d774b..2961b809ccf3 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -876,7 +876,7 @@ static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
drm_rect_rotate_inv(&pipe_cfg->src_rect,
new_plane_state->fb->width, new_plane_state->fb->height,
new_plane_state->rotation);
- if (r_pipe_cfg->src_rect.x1 != 0)
+ 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);
@@ -942,7 +942,7 @@ static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
if (ret)
return ret;
- if (r_pipe_cfg->src_rect.x1 != 0) {
+ if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) {
/*
* In parallel multirect case only the half of the usual width
* is supported for tiled formats. If we are here, we know that
@@ -1022,6 +1022,113 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
}
+static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
+ struct drm_atomic_state *state)
+{
+ struct drm_plane_state *plane_state =
+ drm_atomic_get_plane_state(state, plane);
+ struct dpu_plane_state *pstate = to_dpu_plane_state(plane_state);
+ const struct dpu_format *format;
+ struct drm_crtc_state *crtc_state;
+ int ret;
+
+ if (plane_state->crtc)
+ crtc_state = drm_atomic_get_new_crtc_state(state,
+ plane_state->crtc);
+
+ ret = dpu_plane_atomic_check_nopipe(plane, plane_state, crtc_state);
+ if (ret)
+ return ret;
+
+ if (!plane_state->visible) {
+ /*
+ * resources are freed by dpu_crtc_assign_plane_resources(),
+ * but clean them here.
+ */
+ pstate->pipe.sspp = NULL;
+ pstate->r_pipe.sspp = NULL;
+
+ return 0;
+ }
+
+ format = to_dpu_format(msm_framebuffer_format(plane_state->fb));
+
+ /* force resource reallocation if the format of FB has changed */
+ if (pstate->saved_fmt != format) {
+ crtc_state->planes_changed = true;
+ pstate->saved_fmt = format;
+ }
+
+ 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)
+{
+ 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;
+ struct dpu_sw_pipe *pipe;
+ struct dpu_sw_pipe *r_pipe;
+ const struct dpu_format *fmt;
+
+ if (plane_state->crtc)
+ crtc_state = drm_atomic_get_new_crtc_state(state,
+ plane_state->crtc);
+
+ pstate = to_dpu_plane_state(plane_state);
+ pipe = &pstate->pipe;
+ r_pipe = &pstate->r_pipe;
+
+ pipe->sspp = NULL;
+ r_pipe->sspp = NULL;
+
+ if (!plane_state->fb)
+ return -EINVAL;
+
+ fmt = to_dpu_format(msm_framebuffer_format(plane_state->fb));
+ reqs.yuv = DPU_FORMAT_IS_YUV(fmt);
+ reqs.scale = (plane_state->src_w >> 16 != plane_state->crtc_w) ||
+ (plane_state->src_h >> 16 != plane_state->crtc_h);
+
+ reqs.rot90 = drm_rotation_90_or_270(plane_state->rotation);
+
+ pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
+ if (!pipe->sspp)
+ return -ENODEV;
+
+ return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
+}
+
+int dpu_assign_plane_resources(struct dpu_global_state *global_state,
+ struct drm_atomic_state *state,
+ struct drm_crtc *crtc,
+ struct drm_plane_state **states,
+ unsigned int num_planes)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < num_planes; i++) {
+ struct drm_plane_state *plane_state = states[i];
+
+ if (!plane_state ||
+ !plane_state->visible)
+ continue;
+
+ ret = dpu_plane_virtual_assign_resources(crtc, global_state,
+ state, plane_state);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
static void dpu_plane_flush_csc(struct dpu_plane *pdpu, struct dpu_sw_pipe *pipe)
{
const struct dpu_format *format =
@@ -1342,12 +1449,14 @@ static void dpu_plane_atomic_print_state(struct drm_printer *p,
drm_printf(p, "\tstage=%d\n", pstate->stage);
- 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 (pipe->sspp) {
+ 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);
@@ -1436,31 +1545,29 @@ static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = {
.atomic_update = dpu_plane_atomic_update,
};
+static const struct drm_plane_helper_funcs dpu_plane_virtual_helper_funcs = {
+ .prepare_fb = dpu_plane_prepare_fb,
+ .cleanup_fb = dpu_plane_cleanup_fb,
+ .atomic_check = dpu_plane_virtual_atomic_check,
+ .atomic_update = dpu_plane_atomic_update,
+};
+
/* initialize plane */
-struct drm_plane *dpu_plane_init(struct drm_device *dev,
- uint32_t pipe, enum drm_plane_type type,
- unsigned long possible_crtcs)
+static struct drm_plane *dpu_plane_init_common(struct drm_device *dev,
+ enum drm_plane_type type,
+ unsigned long possible_crtcs,
+ bool inline_rotation,
+ const uint32_t *format_list,
+ uint32_t num_formats,
+ enum dpu_sspp pipe)
{
struct drm_plane *plane = NULL;
- const uint32_t *format_list;
struct dpu_plane *pdpu;
struct msm_drm_private *priv = dev->dev_private;
struct dpu_kms *kms = to_dpu_kms(priv->kms);
- struct dpu_hw_sspp *pipe_hw;
- uint32_t num_formats;
uint32_t supported_rotations;
int ret;
- /* initialize underlying h/w driver */
- pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);
- if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {
- DPU_ERROR("[%u]SSPP is invalid\n", pipe);
- return ERR_PTR(-EINVAL);
- }
-
- format_list = pipe_hw->cap->sblk->format_list;
- num_formats = pipe_hw->cap->sblk->num_formats;
-
pdpu = drmm_universal_plane_alloc(dev, struct dpu_plane, base,
0xff, &dpu_plane_funcs,
format_list, num_formats,
@@ -1486,7 +1593,7 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
- if (pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION))
+ if (inline_rotation)
supported_rotations |= DRM_MODE_ROTATE_MASK;
drm_plane_create_rotation_property(plane,
@@ -1494,10 +1601,81 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
drm_plane_enable_fb_damage_clips(plane);
- /* success! finalize initialization */
+ DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
+ pipe, plane->base.id);
+ return plane;
+}
+
+struct drm_plane *dpu_plane_init(struct drm_device *dev,
+ uint32_t pipe, enum drm_plane_type type,
+ unsigned long possible_crtcs)
+{
+ struct drm_plane *plane = NULL;
+ struct msm_drm_private *priv = dev->dev_private;
+ struct dpu_kms *kms = to_dpu_kms(priv->kms);
+ struct dpu_hw_sspp *pipe_hw;
+
+ /* initialize underlying h/w driver */
+ pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);
+ if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {
+ DPU_ERROR("[%u]SSPP is invalid\n", pipe);
+ return ERR_PTR(-EINVAL);
+ }
+
+
+ plane = dpu_plane_init_common(dev, type, possible_crtcs,
+ pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION),
+ pipe_hw->cap->sblk->format_list,
+ pipe_hw->cap->sblk->num_formats,
+ pipe);
+ if (IS_ERR(plane))
+ return plane;
+
drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
pipe, plane->base.id);
+
+ return plane;
+}
+
+struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
+ enum drm_plane_type type,
+ unsigned long possible_crtcs)
+{
+ struct drm_plane *plane = NULL;
+ struct msm_drm_private *priv = dev->dev_private;
+ struct dpu_kms *kms = to_dpu_kms(priv->kms);
+ bool has_inline_rotation = false;
+ const u32 *format_list = NULL;
+ u32 num_formats = 0;
+ int i;
+
+ /* Determine the largest configuration that we can implement */
+ for (i = 0; i < kms->catalog->sspp_count; i++) {
+ const struct dpu_sspp_cfg *cfg = &kms->catalog->sspp[i];
+
+ if (test_bit(DPU_SSPP_INLINE_ROTATION, &cfg->features))
+ has_inline_rotation = true;
+
+ if (!format_list ||
+ cfg->sblk->csc_blk.len) {
+ format_list = cfg->sblk->format_list;
+ num_formats = cfg->sblk->num_formats;
+ }
+ }
+
+ plane = dpu_plane_init_common(dev, type, possible_crtcs,
+ has_inline_rotation,
+ format_list,
+ num_formats,
+ SSPP_NONE);
+ if (IS_ERR(plane))
+ return plane;
+
+ drm_plane_helper_add(plane, &dpu_plane_virtual_helper_funcs);
+
+ DPU_DEBUG("%s created virtual id:%u\n", plane->name, plane->base.id);
+
return plane;
}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
index a3ae45dc95d0..15f7d60d8b85 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
@@ -30,6 +30,7 @@
* @plane_fetch_bw: calculated BW per plane
* @plane_clk: calculated clk per plane
* @needs_dirtyfb: whether attached CRTC needs pixel data explicitly flushed
+ * @saved_fmt: format used by the plane's FB, saved for for virtual plane support
*/
struct dpu_plane_state {
struct drm_plane_state base;
@@ -46,6 +47,8 @@ struct dpu_plane_state {
u64 plane_clk;
bool needs_dirtyfb;
+
+ const struct dpu_format *saved_fmt;
};
#define to_dpu_plane_state(x) \
@@ -75,6 +78,16 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
uint32_t pipe, enum drm_plane_type type,
unsigned long possible_crtcs);
+/**
+ * dpu_plane_init_virtual - create new dpu virtualized plane
+ * @dev: Pointer to DRM device
+ * @type: Plane type - PRIMARY/OVERLAY/CURSOR
+ * @possible_crtcs: bitmask of crtc that can be attached to the given pipe
+ */
+struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
+ enum drm_plane_type type,
+ unsigned long possible_crtcs);
+
/**
* dpu_plane_color_fill - enables color fill on plane
* @plane: Pointer to DRM plane object
@@ -91,4 +104,10 @@ void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable);
static inline void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) {}
#endif
+int dpu_assign_plane_resources(struct dpu_global_state *global_state,
+ struct drm_atomic_state *state,
+ struct drm_crtc *crtc,
+ struct drm_plane_state **states,
+ unsigned int num_planes);
+
#endif /* _DPU_PLANE_H_ */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
index 44938ba7a2b7..7264a4d44a14 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
@@ -694,6 +694,83 @@ int dpu_rm_reserve(
return ret;
}
+struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
+ struct dpu_global_state *global_state,
+ struct drm_crtc *crtc,
+ struct dpu_rm_sspp_requirements *reqs)
+{
+ uint32_t crtc_id = crtc->base.id;
+ unsigned int weight, best_weght = UINT_MAX;
+ struct dpu_hw_sspp *hw_sspp;
+ unsigned long mask = 0;
+ int i, best_idx = -1;
+
+ /*
+ * Don't take cursor feature into consideration until there is proper support for SSPP_CURSORn.
+ */
+ mask |= BIT(DPU_SSPP_CURSOR);
+
+ if (reqs->scale)
+ mask |= BIT(DPU_SSPP_SCALER_RGB) |
+ BIT(DPU_SSPP_SCALER_QSEED2) |
+ BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE);
+
+ if (reqs->yuv)
+ mask |= BIT(DPU_SSPP_CSC) |
+ BIT(DPU_SSPP_CSC_10BIT);
+
+ if (reqs->rot90)
+ mask |= BIT(DPU_SSPP_INLINE_ROTATION);
+
+ for (i = 0; i < ARRAY_SIZE(rm->hw_sspp); i++) {
+ if (!rm->hw_sspp[i])
+ continue;
+
+ if (global_state->sspp_to_crtc_id[i])
+ continue;
+
+ hw_sspp = rm->hw_sspp[i];
+
+ /* skip incompatible planes */
+ if (reqs->scale && !hw_sspp->cap->sblk->scaler_blk.len)
+ continue;
+
+ if (reqs->yuv && !hw_sspp->cap->sblk->csc_blk.len)
+ continue;
+
+ if (reqs->rot90 && !(hw_sspp->cap->features & DPU_SSPP_INLINE_ROTATION))
+ continue;
+
+ /*
+ * For non-yuv, non-scaled planes prefer simple (DMA or RGB)
+ * plane, falling back to VIG only if there are no such planes.
+ *
+ * This way we'd leave VIG sspps to be later used for YUV formats.
+ */
+ weight = hweight64(hw_sspp->cap->features & ~mask);
+ if (weight < best_weght) {
+ best_weght = weight;
+ best_idx = i;
+ }
+ }
+
+ if (best_idx < 0)
+ return NULL;
+
+ global_state->sspp_to_crtc_id[best_idx] = crtc_id;
+
+ return rm->hw_sspp[best_idx];
+}
+
+void dpu_rm_release_all_sspp(struct dpu_global_state *global_state,
+ struct drm_crtc *crtc)
+{
+ uint32_t crtc_id = crtc->base.id;
+
+ _dpu_rm_clear_mapping(global_state->sspp_to_crtc_id,
+ ARRAY_SIZE(global_state->sspp_to_crtc_id), crtc_id);
+}
+
int dpu_rm_get_assigned_resources(struct dpu_rm *rm,
struct dpu_global_state *global_state, uint32_t enc_id,
enum dpu_hw_blk_type type, struct dpu_hw_blk **blks, int blks_size)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
index e63db8ace6b9..bf9110547385 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
@@ -37,6 +37,12 @@ struct dpu_rm {
struct dpu_hw_blk *cdm_blk;
};
+struct dpu_rm_sspp_requirements {
+ bool yuv;
+ bool scale;
+ bool rot90;
+};
+
/**
* dpu_rm_init - Read hardware catalog and create reservation tracking objects
* for all HW blocks.
@@ -82,6 +88,28 @@ int dpu_rm_reserve(struct dpu_rm *rm,
void dpu_rm_release(struct dpu_global_state *global_state,
struct drm_encoder *enc);
+/**
+ * dpu_rm_reserve_sspp - Reserve the required SSPP for the provided CRTC
+ * @rm: DPU Resource Manager handle
+ * @global_state: private global state
+ * @crtc: DRM CRTC handle
+ * @reqs: SSPP required features
+ */
+struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
+ struct dpu_global_state *global_state,
+ struct drm_crtc *crtc,
+ struct dpu_rm_sspp_requirements *reqs);
+
+/**
+ * dpu_rm_release_all_sspp - Given the CRTC, release all SSPP
+ * blocks previously reserved for that use case.
+ * @rm: DPU Resource Manager handle
+ * @crtc: DRM CRTC handle
+ * @Return: 0 on Success otherwise -ERROR
+ */
+void dpu_rm_release_all_sspp(struct dpu_global_state *global_state,
+ struct drm_crtc *crtc);
+
/**
* Get hw resources of the given type that are assigned to this encoder.
*/
--
2.39.2
^ permalink raw reply related [flat|nested] 50+ messages in thread* Re: [v4,08/13] drm/msm/dpu: add support for virtual planes
2024-03-14 0:02 ` [PATCH v4 08/13] drm/msm/dpu: add support for virtual planes Dmitry Baryshkov
@ 2024-03-14 8:04 ` Sui Jingfeng
2024-06-06 22:21 ` [PATCH v4 08/13] " Abhinav Kumar
1 sibling, 0 replies; 50+ messages in thread
From: Sui Jingfeng @ 2024-03-14 8:04 UTC (permalink / raw)
To: Dmitry Baryshkov, Rob Clark, Sean Paul, Abhinav Kumar,
Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
Hi,
On 2024/3/14 08:02, Dmitry Baryshkov wrote:
[...]
>
> +/**
> + * dpu_rm_reserve_sspp - Reserve the required SSPP for the provided CRTC
> + * @rm: DPU Resource Manager handle
> + * @global_state: private global state
> + * @crtc: DRM CRTC handle
> + * @reqs: SSPP required features
> + */
> +struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
> + struct dpu_global_state *global_state,
> + struct drm_crtc *crtc,
> + struct dpu_rm_sspp_requirements *reqs);
> +
> +/**
> + * dpu_rm_release_all_sspp - Given the CRTC, release all SSPP
> + * blocks previously reserved for that use case.
> + * @rm: DPU Resource Manager handle
> + * @crtc: DRM CRTC handle
> + * @Return: 0 on Success otherwise -ERROR
> + */
But this function do not return any value, right?
> +void dpu_rm_release_all_sspp(struct dpu_global_state *global_state,
> + struct drm_crtc *crtc);
> +
> /**
> * Get hw resources of the given type that are assigned to this encoder.
> */
--
Best regards,
Sui
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH v4 08/13] drm/msm/dpu: add support for virtual planes
2024-03-14 0:02 ` [PATCH v4 08/13] drm/msm/dpu: add support for virtual planes Dmitry Baryshkov
2024-03-14 8:04 ` [v4,08/13] " Sui Jingfeng
@ 2024-06-06 22:21 ` Abhinav Kumar
2024-06-07 7:16 ` Dmitry Baryshkov
1 sibling, 1 reply; 50+ messages in thread
From: Abhinav Kumar @ 2024-06-06 22:21 UTC (permalink / raw)
To: Dmitry Baryshkov, Rob Clark, Sean Paul, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> Only several SSPP blocks support such features as YUV output or scaling,
> thus different DRM planes have different features. Properly utilizing
> all planes requires the attention of the compositor, who should
> prefer simpler planes to YUV-supporting ones. Otherwise it is very easy
> to end up in a situation when all featureful planes are already
> allocated for simple windows, leaving no spare plane for YUV playback.
>
> To solve this problem make all planes virtual. Each plane is registered
> as if it supports all possible features, but then at the runtime during
> the atomic_check phase the driver selects backing SSPP block for each
> plane.
>
> Note, this does not provide support for using two different SSPP blocks
> for a single plane or using two rectangles of an SSPP to drive two
> planes. Each plane still gets its own SSPP and can utilize either a solo
> rectangle or both multirect rectangles depending on the resolution.
>
> Note #2: By default support for virtual planes is turned off and the
> driver still uses old code path with preallocated SSPP block for each
> plane. To enable virtual planes, pass 'msm.dpu_use_virtual_planes=1'
> kernel parameter.
>
I like the overall approach in this patch. Some comments below.
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
> drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 50 +++++
> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 10 +-
> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 4 +
> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 230 +++++++++++++++++++---
> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 19 ++
> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 77 ++++++++
> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 28 +++
> 7 files changed, 390 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> index 88c2e51ab166..794c5643584f 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> @@ -1168,6 +1168,49 @@ static bool dpu_crtc_needs_dirtyfb(struct drm_crtc_state *cstate)
> return false;
> }
>
> +static int dpu_crtc_reassign_planes(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
> +{
> + int total_planes = crtc->dev->mode_config.num_total_plane;
> + struct drm_atomic_state *state = crtc_state->state;
> + struct dpu_global_state *global_state;
> + struct drm_plane_state **states;
> + struct drm_plane *plane;
> + int ret;
> +
> + global_state = dpu_kms_get_global_state(crtc_state->state);
> + if (IS_ERR(global_state))
> + return PTR_ERR(global_state);
> +
> + dpu_rm_release_all_sspp(global_state, crtc);
> +
Do we need to call dpu_rm_release_all_sspp() even in the
_dpu_plane_atomic_disable()?
> + if (!crtc_state->enable)
> + return 0;
> +
> + states = kcalloc(total_planes, sizeof(*states), GFP_KERNEL);
> + if (!states)
> + return -ENOMEM;
> +
> + drm_atomic_crtc_state_for_each_plane(plane, crtc_state) {
> + struct drm_plane_state *plane_state =
> + drm_atomic_get_plane_state(state, plane);
> +
> + if (IS_ERR(plane_state)) {
> + ret = PTR_ERR(plane_state);
> + goto done;
> + }
> +
> + states[plane_state->normalized_zpos] = plane_state;
> + }
> +
> + ret = dpu_assign_plane_resources(global_state, state, crtc, states, total_planes);
> +
> +done:
> + kfree(states);
> + return ret;
> +
> + return 0;
> +}
> +
> static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
> struct drm_atomic_state *state)
> {
> @@ -1183,6 +1226,13 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
>
> bool needs_dirtyfb = dpu_crtc_needs_dirtyfb(crtc_state);
>
> + if (dpu_use_virtual_planes &&
> + (crtc_state->planes_changed || crtc_state->zpos_changed)) {
Here, I assume you are relying on DRM to set zpos_changed. But can you
please elaborate why we have to reassign planes when zpos_changes?
> + rc = dpu_crtc_reassign_planes(crtc, crtc_state);
> + if (rc < 0)
> + return rc;
> + }
> +
> if (!crtc_state->enable || !drm_atomic_crtc_effectively_active(crtc_state)) {
> DRM_DEBUG_ATOMIC("crtc%d -> enable %d, active %d, skip atomic_check\n",
> crtc->base.id, crtc_state->enable,
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> index 9a1fe6868979..becdd98f3c40 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> @@ -51,6 +51,9 @@
> #define DPU_DEBUGFS_DIR "msm_dpu"
> #define DPU_DEBUGFS_HWMASKNAME "hw_log_mask"
>
> +bool dpu_use_virtual_planes = false;
> +module_param(dpu_use_virtual_planes, bool, 0);
> +
> static int dpu_kms_hw_init(struct msm_kms *kms);
> static void _dpu_kms_mmu_destroy(struct dpu_kms *dpu_kms);
>
> @@ -770,8 +773,11 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms)
> type, catalog->sspp[i].features,
> catalog->sspp[i].features & BIT(DPU_SSPP_CURSOR));
>
> - plane = dpu_plane_init(dev, catalog->sspp[i].id, type,
> - (1UL << max_crtc_count) - 1);
> + if (dpu_use_virtual_planes)
> + plane = dpu_plane_init_virtual(dev, type, (1UL << max_crtc_count) - 1);
> + else
> + plane = dpu_plane_init(dev, catalog->sspp[i].id, type,
> + (1UL << max_crtc_count) - 1);
> if (IS_ERR(plane)) {
> DPU_ERROR("dpu_plane_init failed\n");
> ret = PTR_ERR(plane);
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
> index e2adc937ea63..195257660057 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
> @@ -64,6 +64,8 @@
> #define ktime_compare_safe(A, B) \
> ktime_compare(ktime_sub((A), (B)), ktime_set(0, 0))
>
> +extern bool dpu_use_virtual_planes;
> +
> struct dpu_kms {
> struct msm_kms base;
> struct drm_device *dev;
> @@ -138,6 +140,8 @@ struct dpu_global_state {
> uint32_t dspp_to_enc_id[DSPP_MAX - DSPP_0];
> uint32_t dsc_to_enc_id[DSC_MAX - DSC_0];
> uint32_t cdm_to_enc_id;
> +
> + uint32_t sspp_to_crtc_id[SSPP_MAX - SSPP_NONE];
I will re-visit this sspp_to_crtc_id mapping after checking the rest of
the patches.
> };
>
> struct dpu_global_state
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> index a41ffa2d774b..2961b809ccf3 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> @@ -876,7 +876,7 @@ static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
> drm_rect_rotate_inv(&pipe_cfg->src_rect,
> new_plane_state->fb->width, new_plane_state->fb->height,
> new_plane_state->rotation);
> - if (r_pipe_cfg->src_rect.x1 != 0)
> + 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);
> @@ -942,7 +942,7 @@ static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
> if (ret)
> return ret;
>
> - if (r_pipe_cfg->src_rect.x1 != 0) {
> + if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) {
> /*
> * In parallel multirect case only the half of the usual width
> * is supported for tiled formats. If we are here, we know that
> @@ -1022,6 +1022,113 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
> }
>
This part should goto patch 6 right?
> +static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
> + struct drm_atomic_state *state)
> +{
> + struct drm_plane_state *plane_state =
> + drm_atomic_get_plane_state(state, plane);
> + struct dpu_plane_state *pstate = to_dpu_plane_state(plane_state);
> + const struct dpu_format *format;
> + struct drm_crtc_state *crtc_state;
> + int ret;
> +
> + if (plane_state->crtc)
> + crtc_state = drm_atomic_get_new_crtc_state(state,
> + plane_state->crtc);
> +
> + ret = dpu_plane_atomic_check_nopipe(plane, plane_state, crtc_state);
> + if (ret)
> + return ret;
> +
> + if (!plane_state->visible) {
> + /*
> + * resources are freed by dpu_crtc_assign_plane_resources(),
> + * but clean them here.
> + */
> + pstate->pipe.sspp = NULL;
> + pstate->r_pipe.sspp = NULL;
> +
> + return 0;
> + }
> +
> + format = to_dpu_format(msm_framebuffer_format(plane_state->fb));
> +
> + /* force resource reallocation if the format of FB has changed */
> + if (pstate->saved_fmt != format) {
> + crtc_state->planes_changed = true;
planes_changed means planes on this CRTC are updated. We are using this
to track that the underlying SSPP of the plane needs to be changed?
Is this still correct because this might conflict with the DRM's
expectation of planes_changed.
> + pstate->saved_fmt = format;
> + }
> +
> + 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)
> +{
> + 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;
> + struct dpu_sw_pipe *pipe;
> + struct dpu_sw_pipe *r_pipe;
> + const struct dpu_format *fmt;
> +
> + if (plane_state->crtc)
> + crtc_state = drm_atomic_get_new_crtc_state(state,
> + plane_state->crtc);
> +
> + pstate = to_dpu_plane_state(plane_state);
> + pipe = &pstate->pipe;
> + r_pipe = &pstate->r_pipe;
> +
> + pipe->sspp = NULL;
> + r_pipe->sspp = NULL;
> +
> + if (!plane_state->fb)
> + return -EINVAL;
> +
> + fmt = to_dpu_format(msm_framebuffer_format(plane_state->fb));
> + reqs.yuv = DPU_FORMAT_IS_YUV(fmt);
> + reqs.scale = (plane_state->src_w >> 16 != plane_state->crtc_w) ||
> + (plane_state->src_h >> 16 != plane_state->crtc_h);
> +
> + reqs.rot90 = drm_rotation_90_or_270(plane_state->rotation);
> +
> + pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
> + if (!pipe->sspp)
> + return -ENODEV;
> +
> + return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
> +}
> +
> +int dpu_assign_plane_resources(struct dpu_global_state *global_state,
> + struct drm_atomic_state *state,
> + struct drm_crtc *crtc,
> + struct drm_plane_state **states,
> + unsigned int num_planes)
> +{
> + unsigned int i;
> + int ret;
> +
> + for (i = 0; i < num_planes; i++) {
> + struct drm_plane_state *plane_state = states[i];
> +
> + if (!plane_state ||
> + !plane_state->visible)
> + continue;
> +
> + ret = dpu_plane_virtual_assign_resources(crtc, global_state,
> + state, plane_state);
> + if (ret)
> + break;
> + }
> +
> + return ret;
> +}
> +
> static void dpu_plane_flush_csc(struct dpu_plane *pdpu, struct dpu_sw_pipe *pipe)
> {
> const struct dpu_format *format =
> @@ -1342,12 +1449,14 @@ static void dpu_plane_atomic_print_state(struct drm_printer *p,
>
> drm_printf(p, "\tstage=%d\n", pstate->stage);
>
> - 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 (pipe->sspp) {
> + 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));
> + }
I dont mind this being pushed out as a separate patch to protect
pipe->sspp. Even though it is static assignment today, there is no harm
against adding this protection even today IMO.
>
> if (r_pipe->sspp) {
> drm_printf(p, "\tsspp[1]=%s\n", r_pipe->sspp->cap->name);
> @@ -1436,31 +1545,29 @@ static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = {
> .atomic_update = dpu_plane_atomic_update,
> };
>
> +static const struct drm_plane_helper_funcs dpu_plane_virtual_helper_funcs = {
> + .prepare_fb = dpu_plane_prepare_fb,
> + .cleanup_fb = dpu_plane_cleanup_fb,
> + .atomic_check = dpu_plane_virtual_atomic_check,
> + .atomic_update = dpu_plane_atomic_update,
> +};
> +
> /* initialize plane */
> -struct drm_plane *dpu_plane_init(struct drm_device *dev,
> - uint32_t pipe, enum drm_plane_type type,
> - unsigned long possible_crtcs)
> +static struct drm_plane *dpu_plane_init_common(struct drm_device *dev,
> + enum drm_plane_type type,
> + unsigned long possible_crtcs,
> + bool inline_rotation,
> + const uint32_t *format_list,
> + uint32_t num_formats,
> + enum dpu_sspp pipe)
> {
> struct drm_plane *plane = NULL;
> - const uint32_t *format_list;
> struct dpu_plane *pdpu;
> struct msm_drm_private *priv = dev->dev_private;
> struct dpu_kms *kms = to_dpu_kms(priv->kms);
> - struct dpu_hw_sspp *pipe_hw;
> - uint32_t num_formats;
> uint32_t supported_rotations;
> int ret;
>
> - /* initialize underlying h/w driver */
> - pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);
> - if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {
> - DPU_ERROR("[%u]SSPP is invalid\n", pipe);
> - return ERR_PTR(-EINVAL);
> - }
> -
> - format_list = pipe_hw->cap->sblk->format_list;
> - num_formats = pipe_hw->cap->sblk->num_formats;
> -
> pdpu = drmm_universal_plane_alloc(dev, struct dpu_plane, base,
> 0xff, &dpu_plane_funcs,
> format_list, num_formats,
> @@ -1486,7 +1593,7 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
>
> supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
>
> - if (pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION))
> + if (inline_rotation)
> supported_rotations |= DRM_MODE_ROTATE_MASK;
>
> drm_plane_create_rotation_property(plane,
> @@ -1494,10 +1601,81 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
>
> drm_plane_enable_fb_damage_clips(plane);
>
> - /* success! finalize initialization */
> + DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
> + pipe, plane->base.id);
> + return plane;
> +}
> +
> +struct drm_plane *dpu_plane_init(struct drm_device *dev,
> + uint32_t pipe, enum drm_plane_type type,
> + unsigned long possible_crtcs)
> +{
> + struct drm_plane *plane = NULL;
> + struct msm_drm_private *priv = dev->dev_private;
> + struct dpu_kms *kms = to_dpu_kms(priv->kms);
> + struct dpu_hw_sspp *pipe_hw;
> +
> + /* initialize underlying h/w driver */
> + pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);
> + if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {
> + DPU_ERROR("[%u]SSPP is invalid\n", pipe);
> + return ERR_PTR(-EINVAL);
> + }
> +
> +
> + plane = dpu_plane_init_common(dev, type, possible_crtcs,
> + pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION),
> + pipe_hw->cap->sblk->format_list,
> + pipe_hw->cap->sblk->num_formats,
> + pipe);
> + if (IS_ERR(plane))
> + return plane;
> +
> drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
>
> DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
> pipe, plane->base.id);
> +
> + return plane;
> +}
> +
> +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
> + enum drm_plane_type type,
> + unsigned long possible_crtcs)
> +{
> + struct drm_plane *plane = NULL;
> + struct msm_drm_private *priv = dev->dev_private;
> + struct dpu_kms *kms = to_dpu_kms(priv->kms);
> + bool has_inline_rotation = false;
> + const u32 *format_list = NULL;
> + u32 num_formats = 0;
> + int i;
> +
> + /* Determine the largest configuration that we can implement */
> + for (i = 0; i < kms->catalog->sspp_count; i++) {
> + const struct dpu_sspp_cfg *cfg = &kms->catalog->sspp[i];
> +
> + if (test_bit(DPU_SSPP_INLINE_ROTATION, &cfg->features))
> + has_inline_rotation = true;
> +
> + if (!format_list ||
> + cfg->sblk->csc_blk.len) {
But format_list is being assigned to NULL just a few lines above. Why is
this check needed?
I dont get why this part can also goto dpu_plane_init_common() as it
looks identical to me.
> + format_list = cfg->sblk->format_list;
> + num_formats = cfg->sblk->num_formats;
> + }
> + }
> +
> + plane = dpu_plane_init_common(dev, type, possible_crtcs,
> + has_inline_rotation,
> + format_list,
> + num_formats,
> + SSPP_NONE);
Ok, here is the part which we were discussing in
https://patchwork.freedesktop.org/patch/582820/?series=131109&rev=1#comment_1087370
So yes, that part belongs to this patch.
> + if (IS_ERR(plane))
> + return plane;
> +
> + drm_plane_helper_add(plane, &dpu_plane_virtual_helper_funcs);
> +
> + DPU_DEBUG("%s created virtual id:%u\n", plane->name, plane->base.id);
> +
> return plane;
> }
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> index a3ae45dc95d0..15f7d60d8b85 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> @@ -30,6 +30,7 @@
> * @plane_fetch_bw: calculated BW per plane
> * @plane_clk: calculated clk per plane
> * @needs_dirtyfb: whether attached CRTC needs pixel data explicitly flushed
> + * @saved_fmt: format used by the plane's FB, saved for for virtual plane support
> */
> struct dpu_plane_state {
> struct drm_plane_state base;
> @@ -46,6 +47,8 @@ struct dpu_plane_state {
> u64 plane_clk;
>
> bool needs_dirtyfb;
> +
> + const struct dpu_format *saved_fmt;
> };
Why is saved_fmt needed?
The use-case which comes to my mind is lets say if we have a RGB format
and we need to switch to a YUV format, basically switch from DMA to ViG
SSPP, then yes we have to mark planes_changed as we need to switch the
underlying SSPP that time, but why cant we simply check that by means of
a check to see if the fmt is YUV and whether CSC block is present in the
SSPP.
This will lead to dpu_crtc_reassign_planes() getting called for format
changes even when the new format might be available in the same SSPP.
>
> #define to_dpu_plane_state(x) \
> @@ -75,6 +78,16 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
> uint32_t pipe, enum drm_plane_type type,
> unsigned long possible_crtcs);
>
> +/**
> + * dpu_plane_init_virtual - create new dpu virtualized plane
> + * @dev: Pointer to DRM device
> + * @type: Plane type - PRIMARY/OVERLAY/CURSOR
> + * @possible_crtcs: bitmask of crtc that can be attached to the given pipe
> + */
> +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
> + enum drm_plane_type type,
> + unsigned long possible_crtcs);
> +
> /**
> * dpu_plane_color_fill - enables color fill on plane
> * @plane: Pointer to DRM plane object
> @@ -91,4 +104,10 @@ void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable);
> static inline void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) {}
> #endif
>
> +int dpu_assign_plane_resources(struct dpu_global_state *global_state,
> + struct drm_atomic_state *state,
> + struct drm_crtc *crtc,
> + struct drm_plane_state **states,
> + unsigned int num_planes);
> +
> #endif /* _DPU_PLANE_H_ */
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> index 44938ba7a2b7..7264a4d44a14 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> @@ -694,6 +694,83 @@ int dpu_rm_reserve(
> return ret;
> }
>
> +struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
> + struct dpu_global_state *global_state,
> + struct drm_crtc *crtc,
> + struct dpu_rm_sspp_requirements *reqs)
> +{
> + uint32_t crtc_id = crtc->base.id;
> + unsigned int weight, best_weght = UINT_MAX;
best_weight?
> + struct dpu_hw_sspp *hw_sspp;
> + unsigned long mask = 0;
> + int i, best_idx = -1;
> +
> + /*
> + * Don't take cursor feature into consideration until there is proper support for SSPP_CURSORn.
> + */
> + mask |= BIT(DPU_SSPP_CURSOR);
> +
> + if (reqs->scale)
> + mask |= BIT(DPU_SSPP_SCALER_RGB) |
> + BIT(DPU_SSPP_SCALER_QSEED2) |
> + BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE);
> +
> + if (reqs->yuv)
> + mask |= BIT(DPU_SSPP_CSC) |
> + BIT(DPU_SSPP_CSC_10BIT);
> +
> + if (reqs->rot90)
> + mask |= BIT(DPU_SSPP_INLINE_ROTATION);
> +
> + for (i = 0; i < ARRAY_SIZE(rm->hw_sspp); i++) {
> + if (!rm->hw_sspp[i])
> + continue;
> +
> + if (global_state->sspp_to_crtc_id[i])
> + continue;
> +
> + hw_sspp = rm->hw_sspp[i];
> +
> + /* skip incompatible planes */
> + if (reqs->scale && !hw_sspp->cap->sblk->scaler_blk.len)
> + continue;
> +
> + if (reqs->yuv && !hw_sspp->cap->sblk->csc_blk.len)
> + continue;
> +
> + if (reqs->rot90 && !(hw_sspp->cap->features & DPU_SSPP_INLINE_ROTATION))
> + continue;
> +
> + /*
> + * For non-yuv, non-scaled planes prefer simple (DMA or RGB)
> + * plane, falling back to VIG only if there are no such planes.
> + *
> + * This way we'd leave VIG sspps to be later used for YUV formats.
> + */
> + weight = hweight64(hw_sspp->cap->features & ~mask);
This approach is assuming that ViG feature masks are more than DMA.
Hence the hweight of DMA SSPP's features is less than hweight of ViG SSPPs.
Is this really true? Because there are other bits such as
DMA_SDM845_MASK which might increase the hweight of DMA SSPPs
I would rather make it simpler.
1) if we need scaling || yuv, then we have to get only a Vig
2) else, first try to get a DMA SSPP
3) if (2) fails, we have to try to get a ViG SSPP.
Lets be more explicit about the SSPP type here rather than using hweight.
> + if (weight < best_weght) {
> + best_weght = weight;
> + best_idx = i;
> + }
> + }
> +
> + if (best_idx < 0)
> + return NULL;
> +
> + global_state->sspp_to_crtc_id[best_idx] = crtc_id;
> +
> + return rm->hw_sspp[best_idx];
> +}
> +
> +void dpu_rm_release_all_sspp(struct dpu_global_state *global_state,
> + struct drm_crtc *crtc)
> +{
> + uint32_t crtc_id = crtc->base.id;
> +
> + _dpu_rm_clear_mapping(global_state->sspp_to_crtc_id,
> + ARRAY_SIZE(global_state->sspp_to_crtc_id), crtc_id);
> +}
> +
> int dpu_rm_get_assigned_resources(struct dpu_rm *rm,
> struct dpu_global_state *global_state, uint32_t enc_id,
> enum dpu_hw_blk_type type, struct dpu_hw_blk **blks, int blks_size)
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> index e63db8ace6b9..bf9110547385 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> @@ -37,6 +37,12 @@ struct dpu_rm {
> struct dpu_hw_blk *cdm_blk;
> };
>
> +struct dpu_rm_sspp_requirements {
> + bool yuv;
> + bool scale;
> + bool rot90;
> +};
> +
> /**
> * dpu_rm_init - Read hardware catalog and create reservation tracking objects
> * for all HW blocks.
> @@ -82,6 +88,28 @@ int dpu_rm_reserve(struct dpu_rm *rm,
> void dpu_rm_release(struct dpu_global_state *global_state,
> struct drm_encoder *enc);
>
> +/**
> + * dpu_rm_reserve_sspp - Reserve the required SSPP for the provided CRTC
> + * @rm: DPU Resource Manager handle
> + * @global_state: private global state
> + * @crtc: DRM CRTC handle
> + * @reqs: SSPP required features
> + */
> +struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
> + struct dpu_global_state *global_state,
> + struct drm_crtc *crtc,
> + struct dpu_rm_sspp_requirements *reqs);
> +
> +/**
> + * dpu_rm_release_all_sspp - Given the CRTC, release all SSPP
> + * blocks previously reserved for that use case.
> + * @rm: DPU Resource Manager handle
> + * @crtc: DRM CRTC handle
> + * @Return: 0 on Success otherwise -ERROR
> + */
This is void so does not return anything?
> +void dpu_rm_release_all_sspp(struct dpu_global_state *global_state,
> + struct drm_crtc *crtc);
> +
> /**
> * Get hw resources of the given type that are assigned to this encoder.
> */
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 08/13] drm/msm/dpu: add support for virtual planes
2024-06-06 22:21 ` [PATCH v4 08/13] " Abhinav Kumar
@ 2024-06-07 7:16 ` Dmitry Baryshkov
2024-06-07 19:22 ` Abhinav Kumar
0 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-06-07 7:16 UTC (permalink / raw)
To: Abhinav Kumar
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On Thu, Jun 06, 2024 at 03:21:11PM -0700, Abhinav Kumar wrote:
> On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> > Only several SSPP blocks support such features as YUV output or scaling,
> > thus different DRM planes have different features. Properly utilizing
> > all planes requires the attention of the compositor, who should
> > prefer simpler planes to YUV-supporting ones. Otherwise it is very easy
> > to end up in a situation when all featureful planes are already
> > allocated for simple windows, leaving no spare plane for YUV playback.
> >
> > To solve this problem make all planes virtual. Each plane is registered
> > as if it supports all possible features, but then at the runtime during
> > the atomic_check phase the driver selects backing SSPP block for each
> > plane.
> >
> > Note, this does not provide support for using two different SSPP blocks
> > for a single plane or using two rectangles of an SSPP to drive two
> > planes. Each plane still gets its own SSPP and can utilize either a solo
> > rectangle or both multirect rectangles depending on the resolution.
> >
> > Note #2: By default support for virtual planes is turned off and the
> > driver still uses old code path with preallocated SSPP block for each
> > plane. To enable virtual planes, pass 'msm.dpu_use_virtual_planes=1'
> > kernel parameter.
> >
>
> I like the overall approach in this patch. Some comments below.
>
> > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > ---
> > drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 50 +++++
> > drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 10 +-
> > drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 4 +
> > drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 230 +++++++++++++++++++---
> > drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 19 ++
> > drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 77 ++++++++
> > drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 28 +++
> > 7 files changed, 390 insertions(+), 28 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > index 88c2e51ab166..794c5643584f 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > @@ -1168,6 +1168,49 @@ static bool dpu_crtc_needs_dirtyfb(struct drm_crtc_state *cstate)
> > return false;
> > }
> > +static int dpu_crtc_reassign_planes(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
> > +{
> > + int total_planes = crtc->dev->mode_config.num_total_plane;
> > + struct drm_atomic_state *state = crtc_state->state;
> > + struct dpu_global_state *global_state;
> > + struct drm_plane_state **states;
> > + struct drm_plane *plane;
> > + int ret;
> > +
> > + global_state = dpu_kms_get_global_state(crtc_state->state);
> > + if (IS_ERR(global_state))
> > + return PTR_ERR(global_state);
> > +
> > + dpu_rm_release_all_sspp(global_state, crtc);
> > +
>
> Do we need to call dpu_rm_release_all_sspp() even in the
> _dpu_plane_atomic_disable()?
It allows the driver to optimize the usage of the SSPP rectangles.
>
> > + if (!crtc_state->enable)
> > + return 0;
> > +
> > + states = kcalloc(total_planes, sizeof(*states), GFP_KERNEL);
> > + if (!states)
> > + return -ENOMEM;
> > +
> > + drm_atomic_crtc_state_for_each_plane(plane, crtc_state) {
> > + struct drm_plane_state *plane_state =
> > + drm_atomic_get_plane_state(state, plane);
> > +
> > + if (IS_ERR(plane_state)) {
> > + ret = PTR_ERR(plane_state);
> > + goto done;
> > + }
> > +
> > + states[plane_state->normalized_zpos] = plane_state;
> > + }
> > +
> > + ret = dpu_assign_plane_resources(global_state, state, crtc, states, total_planes);
> > +
> > +done:
> > + kfree(states);
> > + return ret;
> > +
> > + return 0;
> > +}
> > +
> > static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
> > struct drm_atomic_state *state)
> > {
> > @@ -1183,6 +1226,13 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
> > bool needs_dirtyfb = dpu_crtc_needs_dirtyfb(crtc_state);
> > + if (dpu_use_virtual_planes &&
> > + (crtc_state->planes_changed || crtc_state->zpos_changed)) {
>
> Here, I assume you are relying on DRM to set zpos_changed. But can you
> please elaborate why we have to reassign planes when zpos_changes?
Because the SSPP might be split between two planes. If zpos has changed
we might have to break this split and use two different SSPPs for those
planes.
>
> > + rc = dpu_crtc_reassign_planes(crtc, crtc_state);
> > + if (rc < 0)
> > + return rc;
> > + }
> > +
> > if (!crtc_state->enable || !drm_atomic_crtc_effectively_active(crtc_state)) {
> > DRM_DEBUG_ATOMIC("crtc%d -> enable %d, active %d, skip atomic_check\n",
> > crtc->base.id, crtc_state->enable,
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> > index 9a1fe6868979..becdd98f3c40 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> > @@ -51,6 +51,9 @@
> > #define DPU_DEBUGFS_DIR "msm_dpu"
> > #define DPU_DEBUGFS_HWMASKNAME "hw_log_mask"
> > +bool dpu_use_virtual_planes = false;
> > +module_param(dpu_use_virtual_planes, bool, 0);
> > +
> > static int dpu_kms_hw_init(struct msm_kms *kms);
> > static void _dpu_kms_mmu_destroy(struct dpu_kms *dpu_kms);
> > @@ -770,8 +773,11 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms)
> > type, catalog->sspp[i].features,
> > catalog->sspp[i].features & BIT(DPU_SSPP_CURSOR));
> > - plane = dpu_plane_init(dev, catalog->sspp[i].id, type,
> > - (1UL << max_crtc_count) - 1);
> > + if (dpu_use_virtual_planes)
> > + plane = dpu_plane_init_virtual(dev, type, (1UL << max_crtc_count) - 1);
> > + else
> > + plane = dpu_plane_init(dev, catalog->sspp[i].id, type,
> > + (1UL << max_crtc_count) - 1);
> > if (IS_ERR(plane)) {
> > DPU_ERROR("dpu_plane_init failed\n");
> > ret = PTR_ERR(plane);
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
> > index e2adc937ea63..195257660057 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
> > @@ -64,6 +64,8 @@
> > #define ktime_compare_safe(A, B) \
> > ktime_compare(ktime_sub((A), (B)), ktime_set(0, 0))
> > +extern bool dpu_use_virtual_planes;
> > +
> > struct dpu_kms {
> > struct msm_kms base;
> > struct drm_device *dev;
> > @@ -138,6 +140,8 @@ struct dpu_global_state {
> > uint32_t dspp_to_enc_id[DSPP_MAX - DSPP_0];
> > uint32_t dsc_to_enc_id[DSC_MAX - DSC_0];
> > uint32_t cdm_to_enc_id;
> > +
> > + uint32_t sspp_to_crtc_id[SSPP_MAX - SSPP_NONE];
>
> I will re-visit this sspp_to_crtc_id mapping after checking the rest of the
> patches.
>
> > };
> > struct dpu_global_state
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > index a41ffa2d774b..2961b809ccf3 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > @@ -876,7 +876,7 @@ static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
> > drm_rect_rotate_inv(&pipe_cfg->src_rect,
> > new_plane_state->fb->width, new_plane_state->fb->height,
> > new_plane_state->rotation);
> > - if (r_pipe_cfg->src_rect.x1 != 0)
> > + 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);
> > @@ -942,7 +942,7 @@ static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
> > if (ret)
> > return ret;
> > - if (r_pipe_cfg->src_rect.x1 != 0) {
> > + if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) {
> > /*
> > * In parallel multirect case only the half of the usual width
> > * is supported for tiled formats. If we are here, we know that
> > @@ -1022,6 +1022,113 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> > return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
> > }
>
> This part should goto patch 6 right?
Why? This is only relevant for the virtual planes.
>
> > +static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
> > + struct drm_atomic_state *state)
> > +{
> > + struct drm_plane_state *plane_state =
> > + drm_atomic_get_plane_state(state, plane);
> > + struct dpu_plane_state *pstate = to_dpu_plane_state(plane_state);
> > + const struct dpu_format *format;
> > + struct drm_crtc_state *crtc_state;
> > + int ret;
> > +
> > + if (plane_state->crtc)
> > + crtc_state = drm_atomic_get_new_crtc_state(state,
> > + plane_state->crtc);
> > +
> > + ret = dpu_plane_atomic_check_nopipe(plane, plane_state, crtc_state);
> > + if (ret)
> > + return ret;
> > +
> > + if (!plane_state->visible) {
> > + /*
> > + * resources are freed by dpu_crtc_assign_plane_resources(),
> > + * but clean them here.
> > + */
> > + pstate->pipe.sspp = NULL;
> > + pstate->r_pipe.sspp = NULL;
> > +
> > + return 0;
> > + }
> > +
> > + format = to_dpu_format(msm_framebuffer_format(plane_state->fb));
> > +
> > + /* force resource reallocation if the format of FB has changed */
> > + if (pstate->saved_fmt != format) {
> > + crtc_state->planes_changed = true;
>
> planes_changed means planes on this CRTC are updated. We are using this to
> track that the underlying SSPP of the plane needs to be changed?
>
> Is this still correct because this might conflict with the DRM's expectation
> of planes_changed.
No, it still means that the planes were changed. DRM doesn't seem to
care about the format changes. We do.
>
> > + pstate->saved_fmt = format;
> > + }
> > +
> > + 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)
> > +{
> > + 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;
> > + struct dpu_sw_pipe *pipe;
> > + struct dpu_sw_pipe *r_pipe;
> > + const struct dpu_format *fmt;
> > +
> > + if (plane_state->crtc)
> > + crtc_state = drm_atomic_get_new_crtc_state(state,
> > + plane_state->crtc);
> > +
> > + pstate = to_dpu_plane_state(plane_state);
> > + pipe = &pstate->pipe;
> > + r_pipe = &pstate->r_pipe;
> > +
> > + pipe->sspp = NULL;
> > + r_pipe->sspp = NULL;
> > +
> > + if (!plane_state->fb)
> > + return -EINVAL;
> > +
> > + fmt = to_dpu_format(msm_framebuffer_format(plane_state->fb));
> > + reqs.yuv = DPU_FORMAT_IS_YUV(fmt);
> > + reqs.scale = (plane_state->src_w >> 16 != plane_state->crtc_w) ||
> > + (plane_state->src_h >> 16 != plane_state->crtc_h);
> > +
> > + reqs.rot90 = drm_rotation_90_or_270(plane_state->rotation);
> > +
> > + pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
> > + if (!pipe->sspp)
> > + return -ENODEV;
> > +
> > + return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
> > +}
> > +
> > +int dpu_assign_plane_resources(struct dpu_global_state *global_state,
> > + struct drm_atomic_state *state,
> > + struct drm_crtc *crtc,
> > + struct drm_plane_state **states,
> > + unsigned int num_planes)
> > +{
> > + unsigned int i;
> > + int ret;
> > +
> > + for (i = 0; i < num_planes; i++) {
> > + struct drm_plane_state *plane_state = states[i];
> > +
> > + if (!plane_state ||
> > + !plane_state->visible)
> > + continue;
> > +
> > + ret = dpu_plane_virtual_assign_resources(crtc, global_state,
> > + state, plane_state);
> > + if (ret)
> > + break;
> > + }
> > +
> > + return ret;
> > +}
> > +
> > static void dpu_plane_flush_csc(struct dpu_plane *pdpu, struct dpu_sw_pipe *pipe)
> > {
> > const struct dpu_format *format =
> > @@ -1342,12 +1449,14 @@ static void dpu_plane_atomic_print_state(struct drm_printer *p,
> > drm_printf(p, "\tstage=%d\n", pstate->stage);
> > - 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 (pipe->sspp) {
> > + 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));
> > + }
>
> I dont mind this being pushed out as a separate patch to protect pipe->sspp.
> Even though it is static assignment today, there is no harm against adding
> this protection even today IMO.
No, it doesn't make sense. Currently pipe->sspp is always valid.
Unnecessary checks do harm, they make you think that the condition they
are checking might be invalid.
>
> > if (r_pipe->sspp) {
> > drm_printf(p, "\tsspp[1]=%s\n", r_pipe->sspp->cap->name);
> > @@ -1436,31 +1545,29 @@ static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = {
> > .atomic_update = dpu_plane_atomic_update,
> > };
> > +static const struct drm_plane_helper_funcs dpu_plane_virtual_helper_funcs = {
> > + .prepare_fb = dpu_plane_prepare_fb,
> > + .cleanup_fb = dpu_plane_cleanup_fb,
> > + .atomic_check = dpu_plane_virtual_atomic_check,
> > + .atomic_update = dpu_plane_atomic_update,
> > +};
> > +
> > /* initialize plane */
> > -struct drm_plane *dpu_plane_init(struct drm_device *dev,
> > - uint32_t pipe, enum drm_plane_type type,
> > - unsigned long possible_crtcs)
> > +static struct drm_plane *dpu_plane_init_common(struct drm_device *dev,
> > + enum drm_plane_type type,
> > + unsigned long possible_crtcs,
> > + bool inline_rotation,
> > + const uint32_t *format_list,
> > + uint32_t num_formats,
> > + enum dpu_sspp pipe)
> > {
> > struct drm_plane *plane = NULL;
> > - const uint32_t *format_list;
> > struct dpu_plane *pdpu;
> > struct msm_drm_private *priv = dev->dev_private;
> > struct dpu_kms *kms = to_dpu_kms(priv->kms);
> > - struct dpu_hw_sspp *pipe_hw;
> > - uint32_t num_formats;
> > uint32_t supported_rotations;
> > int ret;
> > - /* initialize underlying h/w driver */
> > - pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);
> > - if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {
> > - DPU_ERROR("[%u]SSPP is invalid\n", pipe);
> > - return ERR_PTR(-EINVAL);
> > - }
> > -
> > - format_list = pipe_hw->cap->sblk->format_list;
> > - num_formats = pipe_hw->cap->sblk->num_formats;
> > -
> > pdpu = drmm_universal_plane_alloc(dev, struct dpu_plane, base,
> > 0xff, &dpu_plane_funcs,
> > format_list, num_formats,
> > @@ -1486,7 +1593,7 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
> > supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
> > - if (pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION))
> > + if (inline_rotation)
> > supported_rotations |= DRM_MODE_ROTATE_MASK;
> > drm_plane_create_rotation_property(plane,
> > @@ -1494,10 +1601,81 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
> > drm_plane_enable_fb_damage_clips(plane);
> > - /* success! finalize initialization */
> > + DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
> > + pipe, plane->base.id);
> > + return plane;
> > +}
> > +
> > +struct drm_plane *dpu_plane_init(struct drm_device *dev,
> > + uint32_t pipe, enum drm_plane_type type,
> > + unsigned long possible_crtcs)
> > +{
> > + struct drm_plane *plane = NULL;
> > + struct msm_drm_private *priv = dev->dev_private;
> > + struct dpu_kms *kms = to_dpu_kms(priv->kms);
> > + struct dpu_hw_sspp *pipe_hw;
> > +
> > + /* initialize underlying h/w driver */
> > + pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);
> > + if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {
> > + DPU_ERROR("[%u]SSPP is invalid\n", pipe);
> > + return ERR_PTR(-EINVAL);
> > + }
> > +
> > +
> > + plane = dpu_plane_init_common(dev, type, possible_crtcs,
> > + pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION),
> > + pipe_hw->cap->sblk->format_list,
> > + pipe_hw->cap->sblk->num_formats,
> > + pipe);
> > + if (IS_ERR(plane))
> > + return plane;
> > +
> > drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
> > DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
> > pipe, plane->base.id);
> > +
> > + return plane;
> > +}
> > +
> > +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
> > + enum drm_plane_type type,
> > + unsigned long possible_crtcs)
> > +{
> > + struct drm_plane *plane = NULL;
> > + struct msm_drm_private *priv = dev->dev_private;
> > + struct dpu_kms *kms = to_dpu_kms(priv->kms);
> > + bool has_inline_rotation = false;
> > + const u32 *format_list = NULL;
> > + u32 num_formats = 0;
> > + int i;
> > +
> > + /* Determine the largest configuration that we can implement */
> > + for (i = 0; i < kms->catalog->sspp_count; i++) {
> > + const struct dpu_sspp_cfg *cfg = &kms->catalog->sspp[i];
> > +
> > + if (test_bit(DPU_SSPP_INLINE_ROTATION, &cfg->features))
> > + has_inline_rotation = true;
> > +
> > + if (!format_list ||
> > + cfg->sblk->csc_blk.len) {
>
> But format_list is being assigned to NULL just a few lines above. Why is
> this check needed?
It was assigned before the loop.
>
> I dont get why this part can also goto dpu_plane_init_common() as it looks
> identical to me.
And it is not. For the non-virtual case there is no loop around formats
list assignment.
>
>
> > + format_list = cfg->sblk->format_list;
> > + num_formats = cfg->sblk->num_formats;
> > + }
> > + }
> > +
> > + plane = dpu_plane_init_common(dev, type, possible_crtcs,
> > + has_inline_rotation,
> > + format_list,
> > + num_formats,
> > + SSPP_NONE);
>
> Ok, here is the part which we were discussing in
>
> https://patchwork.freedesktop.org/patch/582820/?series=131109&rev=1#comment_1087370
>
> So yes, that part belongs to this patch.
I'll check it while preparing the next iteration.
>
> > + if (IS_ERR(plane))
> > + return plane;
> > +
> > + drm_plane_helper_add(plane, &dpu_plane_virtual_helper_funcs);
> > +
> > + DPU_DEBUG("%s created virtual id:%u\n", plane->name, plane->base.id);
> > +
> > return plane;
> > }
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> > index a3ae45dc95d0..15f7d60d8b85 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> > @@ -30,6 +30,7 @@
> > * @plane_fetch_bw: calculated BW per plane
> > * @plane_clk: calculated clk per plane
> > * @needs_dirtyfb: whether attached CRTC needs pixel data explicitly flushed
> > + * @saved_fmt: format used by the plane's FB, saved for for virtual plane support
> > */
> > struct dpu_plane_state {
> > struct drm_plane_state base;
> > @@ -46,6 +47,8 @@ struct dpu_plane_state {
> > u64 plane_clk;
> > bool needs_dirtyfb;
> > +
> > + const struct dpu_format *saved_fmt;
> > };
>
> Why is saved_fmt needed?
>
> The use-case which comes to my mind is lets say if we have a RGB format and
> we need to switch to a YUV format, basically switch from DMA to ViG SSPP,
> then yes we have to mark planes_changed as we need to switch the underlying
> SSPP that time, but why cant we simply check that by means of a check to see
> if the fmt is YUV and whether CSC block is present in the SSPP.
Yes, correct. And vice versa, going from YUV to RGB might free the VIG
SSPP.
>
> This will lead to dpu_crtc_reassign_planes() getting called for format
> changes even when the new format might be available in the same SSPP.
So use 'needs_vig' instead of storing the format? Sounds good to me.
>
> > #define to_dpu_plane_state(x) \
> > @@ -75,6 +78,16 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
> > uint32_t pipe, enum drm_plane_type type,
> > unsigned long possible_crtcs);
> > +/**
> > + * dpu_plane_init_virtual - create new dpu virtualized plane
> > + * @dev: Pointer to DRM device
> > + * @type: Plane type - PRIMARY/OVERLAY/CURSOR
> > + * @possible_crtcs: bitmask of crtc that can be attached to the given pipe
> > + */
> > +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
> > + enum drm_plane_type type,
> > + unsigned long possible_crtcs);
> > +
> > /**
> > * dpu_plane_color_fill - enables color fill on plane
> > * @plane: Pointer to DRM plane object
> > @@ -91,4 +104,10 @@ void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable);
> > static inline void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) {}
> > #endif
> > +int dpu_assign_plane_resources(struct dpu_global_state *global_state,
> > + struct drm_atomic_state *state,
> > + struct drm_crtc *crtc,
> > + struct drm_plane_state **states,
> > + unsigned int num_planes);
> > +
> > #endif /* _DPU_PLANE_H_ */
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> > index 44938ba7a2b7..7264a4d44a14 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> > @@ -694,6 +694,83 @@ int dpu_rm_reserve(
> > return ret;
> > }
> > +struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
> > + struct dpu_global_state *global_state,
> > + struct drm_crtc *crtc,
> > + struct dpu_rm_sspp_requirements *reqs)
> > +{
> > + uint32_t crtc_id = crtc->base.id;
> > + unsigned int weight, best_weght = UINT_MAX;
>
> best_weight?
Yes
>
> > + struct dpu_hw_sspp *hw_sspp;
> > + unsigned long mask = 0;
> > + int i, best_idx = -1;
> > +
> > + /*
> > + * Don't take cursor feature into consideration until there is proper support for SSPP_CURSORn.
> > + */
> > + mask |= BIT(DPU_SSPP_CURSOR);
> > +
> > + if (reqs->scale)
> > + mask |= BIT(DPU_SSPP_SCALER_RGB) |
> > + BIT(DPU_SSPP_SCALER_QSEED2) |
> > + BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE);
> > +
> > + if (reqs->yuv)
> > + mask |= BIT(DPU_SSPP_CSC) |
> > + BIT(DPU_SSPP_CSC_10BIT);
> > +
> > + if (reqs->rot90)
> > + mask |= BIT(DPU_SSPP_INLINE_ROTATION);
> > +
> > + for (i = 0; i < ARRAY_SIZE(rm->hw_sspp); i++) {
> > + if (!rm->hw_sspp[i])
> > + continue;
> > +
> > + if (global_state->sspp_to_crtc_id[i])
> > + continue;
> > +
> > + hw_sspp = rm->hw_sspp[i];
> > +
> > + /* skip incompatible planes */
> > + if (reqs->scale && !hw_sspp->cap->sblk->scaler_blk.len)
> > + continue;
> > +
> > + if (reqs->yuv && !hw_sspp->cap->sblk->csc_blk.len)
> > + continue;
> > +
> > + if (reqs->rot90 && !(hw_sspp->cap->features & DPU_SSPP_INLINE_ROTATION))
> > + continue;
> > +
> > + /*
> > + * For non-yuv, non-scaled planes prefer simple (DMA or RGB)
> > + * plane, falling back to VIG only if there are no such planes.
> > + *
> > + * This way we'd leave VIG sspps to be later used for YUV formats.
> > + */
> > + weight = hweight64(hw_sspp->cap->features & ~mask);
>
> This approach is assuming that ViG feature masks are more than DMA.
> Hence the hweight of DMA SSPP's features is less than hweight of ViG SSPPs.
>
> Is this really true? Because there are other bits such as DMA_SDM845_MASK
> which might increase the hweight of DMA SSPPs
Which bits are present in the DMA mask, which are not present in the VIG
mask? Also for the older platforms there are three kinds of planes: VIG,
DMA and RGB. The selection algorithm should not require significant
changes to support that case.
>
> I would rather make it simpler.
>
> 1) if we need scaling || yuv, then we have to get only a Vig
> 2) else, first try to get a DMA SSPP
How would you distinguish between VIG and DMA?
> 3) if (2) fails, we have to try to get a ViG SSPP.
>
> Lets be more explicit about the SSPP type here rather than using hweight.
>
>
> > + if (weight < best_weght) {
> > + best_weght = weight;
> > + best_idx = i;
> > + }
> > + }
> > +
> > + if (best_idx < 0)
> > + return NULL;
> > +
> > + global_state->sspp_to_crtc_id[best_idx] = crtc_id;
> > +
> > + return rm->hw_sspp[best_idx];
> > +}
> > +
> > +void dpu_rm_release_all_sspp(struct dpu_global_state *global_state,
> > + struct drm_crtc *crtc)
> > +{
> > + uint32_t crtc_id = crtc->base.id;
> > +
> > + _dpu_rm_clear_mapping(global_state->sspp_to_crtc_id,
> > + ARRAY_SIZE(global_state->sspp_to_crtc_id), crtc_id);
> > +}
> > +
> > int dpu_rm_get_assigned_resources(struct dpu_rm *rm,
> > struct dpu_global_state *global_state, uint32_t enc_id,
> > enum dpu_hw_blk_type type, struct dpu_hw_blk **blks, int blks_size)
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> > index e63db8ace6b9..bf9110547385 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> > @@ -37,6 +37,12 @@ struct dpu_rm {
> > struct dpu_hw_blk *cdm_blk;
> > };
> > +struct dpu_rm_sspp_requirements {
> > + bool yuv;
> > + bool scale;
> > + bool rot90;
> > +};
> > +
> > /**
> > * dpu_rm_init - Read hardware catalog and create reservation tracking objects
> > * for all HW blocks.
> > @@ -82,6 +88,28 @@ int dpu_rm_reserve(struct dpu_rm *rm,
> > void dpu_rm_release(struct dpu_global_state *global_state,
> > struct drm_encoder *enc);
> > +/**
> > + * dpu_rm_reserve_sspp - Reserve the required SSPP for the provided CRTC
> > + * @rm: DPU Resource Manager handle
> > + * @global_state: private global state
> > + * @crtc: DRM CRTC handle
> > + * @reqs: SSPP required features
> > + */
> > +struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
> > + struct dpu_global_state *global_state,
> > + struct drm_crtc *crtc,
> > + struct dpu_rm_sspp_requirements *reqs);
> > +
> > +/**
> > + * dpu_rm_release_all_sspp - Given the CRTC, release all SSPP
> > + * blocks previously reserved for that use case.
> > + * @rm: DPU Resource Manager handle
> > + * @crtc: DRM CRTC handle
> > + * @Return: 0 on Success otherwise -ERROR
> > + */
>
> This is void so does not return anything?
>
> > +void dpu_rm_release_all_sspp(struct dpu_global_state *global_state,
> > + struct drm_crtc *crtc);
> > +
> > /**
> > * Get hw resources of the given type that are assigned to this encoder.
> > */
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 08/13] drm/msm/dpu: add support for virtual planes
2024-06-07 7:16 ` Dmitry Baryshkov
@ 2024-06-07 19:22 ` Abhinav Kumar
2024-06-07 21:10 ` Dmitry Baryshkov
0 siblings, 1 reply; 50+ messages in thread
From: Abhinav Kumar @ 2024-06-07 19:22 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On 6/7/2024 12:16 AM, Dmitry Baryshkov wrote:
> On Thu, Jun 06, 2024 at 03:21:11PM -0700, Abhinav Kumar wrote:
>> On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
>>> Only several SSPP blocks support such features as YUV output or scaling,
>>> thus different DRM planes have different features. Properly utilizing
>>> all planes requires the attention of the compositor, who should
>>> prefer simpler planes to YUV-supporting ones. Otherwise it is very easy
>>> to end up in a situation when all featureful planes are already
>>> allocated for simple windows, leaving no spare plane for YUV playback.
>>>
>>> To solve this problem make all planes virtual. Each plane is registered
>>> as if it supports all possible features, but then at the runtime during
>>> the atomic_check phase the driver selects backing SSPP block for each
>>> plane.
>>>
>>> Note, this does not provide support for using two different SSPP blocks
>>> for a single plane or using two rectangles of an SSPP to drive two
>>> planes. Each plane still gets its own SSPP and can utilize either a solo
>>> rectangle or both multirect rectangles depending on the resolution.
>>>
>>> Note #2: By default support for virtual planes is turned off and the
>>> driver still uses old code path with preallocated SSPP block for each
>>> plane. To enable virtual planes, pass 'msm.dpu_use_virtual_planes=1'
>>> kernel parameter.
>>>
>>
>> I like the overall approach in this patch. Some comments below.
>>
>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>> ---
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 50 +++++
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 10 +-
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 4 +
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 230 +++++++++++++++++++---
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 19 ++
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 77 ++++++++
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 28 +++
>>> 7 files changed, 390 insertions(+), 28 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>> index 88c2e51ab166..794c5643584f 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>> @@ -1168,6 +1168,49 @@ static bool dpu_crtc_needs_dirtyfb(struct drm_crtc_state *cstate)
>>> return false;
>>> }
>>> +static int dpu_crtc_reassign_planes(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
>>> +{
>>> + int total_planes = crtc->dev->mode_config.num_total_plane;
>>> + struct drm_atomic_state *state = crtc_state->state;
>>> + struct dpu_global_state *global_state;
>>> + struct drm_plane_state **states;
>>> + struct drm_plane *plane;
>>> + int ret;
>>> +
>>> + global_state = dpu_kms_get_global_state(crtc_state->state);
>>> + if (IS_ERR(global_state))
>>> + return PTR_ERR(global_state);
>>> +
>>> + dpu_rm_release_all_sspp(global_state, crtc);
>>> +
>>
>> Do we need to call dpu_rm_release_all_sspp() even in the
>> _dpu_plane_atomic_disable()?
>
> It allows the driver to optimize the usage of the SSPP rectangles.
>
No, what I meant was that we should call dpu_rm_release_all_sspp() in
dpu_plane_atomic_update() as well because in the atomic_check() path
where its called today, its being called only for zpos_changed and
planes_changed but during disable we must call this for sure.
>>
>>> + if (!crtc_state->enable)
>>> + return 0;
>>> +
>>> + states = kcalloc(total_planes, sizeof(*states), GFP_KERNEL);
>>> + if (!states)
>>> + return -ENOMEM;
>>> +
>>> + drm_atomic_crtc_state_for_each_plane(plane, crtc_state) {
>>> + struct drm_plane_state *plane_state =
>>> + drm_atomic_get_plane_state(state, plane);
>>> +
>>> + if (IS_ERR(plane_state)) {
>>> + ret = PTR_ERR(plane_state);
>>> + goto done;
>>> + }
>>> +
>>> + states[plane_state->normalized_zpos] = plane_state;
>>> + }
>>> +
>>> + ret = dpu_assign_plane_resources(global_state, state, crtc, states, total_planes);
>>> +
>>> +done:
>>> + kfree(states);
>>> + return ret;
>>> +
>>> + return 0;
>>> +}
>>> +
>>> static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
>>> struct drm_atomic_state *state)
>>> {
>>> @@ -1183,6 +1226,13 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
>>> bool needs_dirtyfb = dpu_crtc_needs_dirtyfb(crtc_state);
>>> + if (dpu_use_virtual_planes &&
>>> + (crtc_state->planes_changed || crtc_state->zpos_changed)) {
>>
>> Here, I assume you are relying on DRM to set zpos_changed. But can you
>> please elaborate why we have to reassign planes when zpos_changes?
>
> Because the SSPP might be split between two planes. If zpos has changed
> we might have to break this split and use two different SSPPs for those
> planes.
>
Got it. But that support has not been added yet so belongs to a later
patchset?
>>
>>> + rc = dpu_crtc_reassign_planes(crtc, crtc_state);
>>> + if (rc < 0)
>>> + return rc;
>>> + }
>>> +
>>> if (!crtc_state->enable || !drm_atomic_crtc_effectively_active(crtc_state)) {
>>> DRM_DEBUG_ATOMIC("crtc%d -> enable %d, active %d, skip atomic_check\n",
>>> crtc->base.id, crtc_state->enable,
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>>> index 9a1fe6868979..becdd98f3c40 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>>> @@ -51,6 +51,9 @@
>>> #define DPU_DEBUGFS_DIR "msm_dpu"
>>> #define DPU_DEBUGFS_HWMASKNAME "hw_log_mask"
>>> +bool dpu_use_virtual_planes = false;
>>> +module_param(dpu_use_virtual_planes, bool, 0);
>>> +
>>> static int dpu_kms_hw_init(struct msm_kms *kms);
>>> static void _dpu_kms_mmu_destroy(struct dpu_kms *dpu_kms);
>>> @@ -770,8 +773,11 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms)
>>> type, catalog->sspp[i].features,
>>> catalog->sspp[i].features & BIT(DPU_SSPP_CURSOR));
>>> - plane = dpu_plane_init(dev, catalog->sspp[i].id, type,
>>> - (1UL << max_crtc_count) - 1);
>>> + if (dpu_use_virtual_planes)
>>> + plane = dpu_plane_init_virtual(dev, type, (1UL << max_crtc_count) - 1);
>>> + else
>>> + plane = dpu_plane_init(dev, catalog->sspp[i].id, type,
>>> + (1UL << max_crtc_count) - 1);
>>> if (IS_ERR(plane)) {
>>> DPU_ERROR("dpu_plane_init failed\n");
>>> ret = PTR_ERR(plane);
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
>>> index e2adc937ea63..195257660057 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
>>> @@ -64,6 +64,8 @@
>>> #define ktime_compare_safe(A, B) \
>>> ktime_compare(ktime_sub((A), (B)), ktime_set(0, 0))
>>> +extern bool dpu_use_virtual_planes;
>>> +
>>> struct dpu_kms {
>>> struct msm_kms base;
>>> struct drm_device *dev;
>>> @@ -138,6 +140,8 @@ struct dpu_global_state {
>>> uint32_t dspp_to_enc_id[DSPP_MAX - DSPP_0];
>>> uint32_t dsc_to_enc_id[DSC_MAX - DSC_0];
>>> uint32_t cdm_to_enc_id;
>>> +
>>> + uint32_t sspp_to_crtc_id[SSPP_MAX - SSPP_NONE];
>>
>> I will re-visit this sspp_to_crtc_id mapping after checking the rest of the
>> patches.
>>
>>> };
>>> struct dpu_global_state
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>> index a41ffa2d774b..2961b809ccf3 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>> @@ -876,7 +876,7 @@ static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
>>> drm_rect_rotate_inv(&pipe_cfg->src_rect,
>>> new_plane_state->fb->width, new_plane_state->fb->height,
>>> new_plane_state->rotation);
>>> - if (r_pipe_cfg->src_rect.x1 != 0)
>>> + 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);
>>> @@ -942,7 +942,7 @@ static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
>>> if (ret)
>>> return ret;
>>> - if (r_pipe_cfg->src_rect.x1 != 0) {
>>> + if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) {
>>> /*
>>> * In parallel multirect case only the half of the usual width
>>> * is supported for tiled formats. If we are here, we know that
>>> @@ -1022,6 +1022,113 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
>>> return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
>>> }
>>
>> This part should goto patch 6 right?
>
> Why? This is only relevant for the virtual planes.
>
Patch 6 introducted the if (r_pipe_cfg->src_rect.x1 != 0) checks from
afaict. Was that to ensure there was a valid src_rect for the r_pipe
before invoking drm_rect_rotate_inv()?
This patch changes it from using x1!=0 to using drm_rect_width().
Why cant this check be moved to that patch itself is my question.
>>
>>> +static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
>>> + struct drm_atomic_state *state)
>>> +{
>>> + struct drm_plane_state *plane_state =
>>> + drm_atomic_get_plane_state(state, plane);
>>> + struct dpu_plane_state *pstate = to_dpu_plane_state(plane_state);
>>> + const struct dpu_format *format;
>>> + struct drm_crtc_state *crtc_state;
>>> + int ret;
>>> +
>>> + if (plane_state->crtc)
>>> + crtc_state = drm_atomic_get_new_crtc_state(state,
>>> + plane_state->crtc);
>>> +
>>> + ret = dpu_plane_atomic_check_nopipe(plane, plane_state, crtc_state);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + if (!plane_state->visible) {
>>> + /*
>>> + * resources are freed by dpu_crtc_assign_plane_resources(),
>>> + * but clean them here.
>>> + */
>>> + pstate->pipe.sspp = NULL;
>>> + pstate->r_pipe.sspp = NULL;
>>> +
>>> + return 0;
>>> + }
>>> +
>>> + format = to_dpu_format(msm_framebuffer_format(plane_state->fb));
>>> +
>>> + /* force resource reallocation if the format of FB has changed */
>>> + if (pstate->saved_fmt != format) {
>>> + crtc_state->planes_changed = true;
>>
>> planes_changed means planes on this CRTC are updated. We are using this to
>> track that the underlying SSPP of the plane needs to be changed?
>>
>> Is this still correct because this might conflict with the DRM's expectation
>> of planes_changed.
>
> No, it still means that the planes were changed. DRM doesn't seem to
> care about the format changes. We do.
>
Yes, I am aware that we need to detect format changes and re-assign SSPP
if needed if the SSPP does not support the format which was requested.
My question was whether planes_changed is the right way to track that
because that is being used by DRM to track whether the plane's CRTC
changed so I dont know whether its appropriate to overload that meaning.
Also from the other comment below, since we are dropping saved_fmt, do
we need to retain planes_changed setting?
>>
>>> + pstate->saved_fmt = format;
>>> + }
>>> +
>>> + 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)
>>> +{
>>> + 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;
>>> + struct dpu_sw_pipe *pipe;
>>> + struct dpu_sw_pipe *r_pipe;
>>> + const struct dpu_format *fmt;
>>> +
>>> + if (plane_state->crtc)
>>> + crtc_state = drm_atomic_get_new_crtc_state(state,
>>> + plane_state->crtc);
>>> +
>>> + pstate = to_dpu_plane_state(plane_state);
>>> + pipe = &pstate->pipe;
>>> + r_pipe = &pstate->r_pipe;
>>> +
>>> + pipe->sspp = NULL;
>>> + r_pipe->sspp = NULL;
>>> +
>>> + if (!plane_state->fb)
>>> + return -EINVAL;
>>> +
>>> + fmt = to_dpu_format(msm_framebuffer_format(plane_state->fb));
>>> + reqs.yuv = DPU_FORMAT_IS_YUV(fmt);
>>> + reqs.scale = (plane_state->src_w >> 16 != plane_state->crtc_w) ||
>>> + (plane_state->src_h >> 16 != plane_state->crtc_h);
>>> +
>>> + reqs.rot90 = drm_rotation_90_or_270(plane_state->rotation);
>>> +
>>> + pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
>>> + if (!pipe->sspp)
>>> + return -ENODEV;
>>> +
>>> + return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
>>> +}
>>> +
>>> +int dpu_assign_plane_resources(struct dpu_global_state *global_state,
>>> + struct drm_atomic_state *state,
>>> + struct drm_crtc *crtc,
>>> + struct drm_plane_state **states,
>>> + unsigned int num_planes)
>>> +{
>>> + unsigned int i;
>>> + int ret;
>>> +
>>> + for (i = 0; i < num_planes; i++) {
>>> + struct drm_plane_state *plane_state = states[i];
>>> +
>>> + if (!plane_state ||
>>> + !plane_state->visible)
>>> + continue;
>>> +
>>> + ret = dpu_plane_virtual_assign_resources(crtc, global_state,
>>> + state, plane_state);
>>> + if (ret)
>>> + break;
>>> + }
>>> +
>>> + return ret;
>>> +}
>>> +
>>> static void dpu_plane_flush_csc(struct dpu_plane *pdpu, struct dpu_sw_pipe *pipe)
>>> {
>>> const struct dpu_format *format =
>>> @@ -1342,12 +1449,14 @@ static void dpu_plane_atomic_print_state(struct drm_printer *p,
>>> drm_printf(p, "\tstage=%d\n", pstate->stage);
>>> - 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 (pipe->sspp) {
>>> + 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));
>>> + }
>>
>> I dont mind this being pushed out as a separate patch to protect pipe->sspp.
>> Even though it is static assignment today, there is no harm against adding
>> this protection even today IMO.
>
> No, it doesn't make sense. Currently pipe->sspp is always valid.
> Unnecessary checks do harm, they make you think that the condition they
> are checking might be invalid.
>
Ack.
>>
>>> if (r_pipe->sspp) {
>>> drm_printf(p, "\tsspp[1]=%s\n", r_pipe->sspp->cap->name);
>>> @@ -1436,31 +1545,29 @@ static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = {
>>> .atomic_update = dpu_plane_atomic_update,
>>> };
>>> +static const struct drm_plane_helper_funcs dpu_plane_virtual_helper_funcs = {
>>> + .prepare_fb = dpu_plane_prepare_fb,
>>> + .cleanup_fb = dpu_plane_cleanup_fb,
>>> + .atomic_check = dpu_plane_virtual_atomic_check,
>>> + .atomic_update = dpu_plane_atomic_update,
>>> +};
>>> +
>>> /* initialize plane */
>>> -struct drm_plane *dpu_plane_init(struct drm_device *dev,
>>> - uint32_t pipe, enum drm_plane_type type,
>>> - unsigned long possible_crtcs)
>>> +static struct drm_plane *dpu_plane_init_common(struct drm_device *dev,
>>> + enum drm_plane_type type,
>>> + unsigned long possible_crtcs,
>>> + bool inline_rotation,
>>> + const uint32_t *format_list,
>>> + uint32_t num_formats,
>>> + enum dpu_sspp pipe)
>>> {
>>> struct drm_plane *plane = NULL;
>>> - const uint32_t *format_list;
>>> struct dpu_plane *pdpu;
>>> struct msm_drm_private *priv = dev->dev_private;
>>> struct dpu_kms *kms = to_dpu_kms(priv->kms);
>>> - struct dpu_hw_sspp *pipe_hw;
>>> - uint32_t num_formats;
>>> uint32_t supported_rotations;
>>> int ret;
>>> - /* initialize underlying h/w driver */
>>> - pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);
>>> - if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {
>>> - DPU_ERROR("[%u]SSPP is invalid\n", pipe);
>>> - return ERR_PTR(-EINVAL);
>>> - }
>>> -
>>> - format_list = pipe_hw->cap->sblk->format_list;
>>> - num_formats = pipe_hw->cap->sblk->num_formats;
>>> -
>>> pdpu = drmm_universal_plane_alloc(dev, struct dpu_plane, base,
>>> 0xff, &dpu_plane_funcs,
>>> format_list, num_formats,
>>> @@ -1486,7 +1593,7 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
>>> supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
>>> - if (pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION))
>>> + if (inline_rotation)
>>> supported_rotations |= DRM_MODE_ROTATE_MASK;
>>> drm_plane_create_rotation_property(plane,
>>> @@ -1494,10 +1601,81 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
>>> drm_plane_enable_fb_damage_clips(plane);
>>> - /* success! finalize initialization */
>>> + DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
>>> + pipe, plane->base.id);
>>> + return plane;
>>> +}
>>> +
>>> +struct drm_plane *dpu_plane_init(struct drm_device *dev,
>>> + uint32_t pipe, enum drm_plane_type type,
>>> + unsigned long possible_crtcs)
>>> +{
>>> + struct drm_plane *plane = NULL;
>>> + struct msm_drm_private *priv = dev->dev_private;
>>> + struct dpu_kms *kms = to_dpu_kms(priv->kms);
>>> + struct dpu_hw_sspp *pipe_hw;
>>> +
>>> + /* initialize underlying h/w driver */
>>> + pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);
>>> + if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {
>>> + DPU_ERROR("[%u]SSPP is invalid\n", pipe);
>>> + return ERR_PTR(-EINVAL);
>>> + }
>>> +
>>> +
>>> + plane = dpu_plane_init_common(dev, type, possible_crtcs,
>>> + pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION),
>>> + pipe_hw->cap->sblk->format_list,
>>> + pipe_hw->cap->sblk->num_formats,
>>> + pipe);
>>> + if (IS_ERR(plane))
>>> + return plane;
>>> +
>>> drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
>>> DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
>>> pipe, plane->base.id);
>>> +
>>> + return plane;
>>> +}
>>> +
>>> +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
>>> + enum drm_plane_type type,
>>> + unsigned long possible_crtcs)
>>> +{
>>> + struct drm_plane *plane = NULL;
>>> + struct msm_drm_private *priv = dev->dev_private;
>>> + struct dpu_kms *kms = to_dpu_kms(priv->kms);
>>> + bool has_inline_rotation = false;
>>> + const u32 *format_list = NULL;
>>> + u32 num_formats = 0;
>>> + int i;
>>> +
>>> + /* Determine the largest configuration that we can implement */
>>> + for (i = 0; i < kms->catalog->sspp_count; i++) {
>>> + const struct dpu_sspp_cfg *cfg = &kms->catalog->sspp[i];
>>> +
>>> + if (test_bit(DPU_SSPP_INLINE_ROTATION, &cfg->features))
>>> + has_inline_rotation = true;
>>> +
>>> + if (!format_list ||
>>> + cfg->sblk->csc_blk.len) {
>>
>> But format_list is being assigned to NULL just a few lines above. Why is
>> this check needed?
>
> It was assigned before the loop.
>
Yes, I got this part but missed on why we needed the loop at all.
>>
>> I dont get why this part can also goto dpu_plane_init_common() as it looks
>> identical to me.
>
> And it is not. For the non-virtual case there is no loop around formats
> list assignment.
>
Ah okay, I misunderstood the logic. After reading the comment above the
loop I get what you are trying to do here.
But I dont get why you really need to do that?
1) In this patch the relationship between virtual plane and SSPP is
still 1:1 so what is wrong to retain the sspp's actual format for the
plane rather than picking the best format (you are targetting Vig SSPP)
In fact, that will reduce atomic_check() failures with this patch
because compositor will still work the same way as it used to work
before by not trying an unsupported format on a plane.
If one plane maps to two SSPPs, then yes we can go with the superset of
formats but that comes in a later patch right?
2) So even if we want to do it this way from this patch itself, I think
all you are looking for is whether there is a Vig SSPP and if so use
plane_formats_yuv. There is no need for this loop IMO.
3) I noticed that virt_format_list is still present in the driver. If
you are planning to not use that perhaps drop it with this series.
>>
>>
>>> + format_list = cfg->sblk->format_list;
>>> + num_formats = cfg->sblk->num_formats;
>>> + }
>>> + }
>>> +
>>> + plane = dpu_plane_init_common(dev, type, possible_crtcs,
>>> + has_inline_rotation,
>>> + format_list,
>>> + num_formats,
>>> + SSPP_NONE);
>>
>> Ok, here is the part which we were discussing in
>>
>> https://patchwork.freedesktop.org/patch/582820/?series=131109&rev=1#comment_1087370
>>
>> So yes, that part belongs to this patch.
>
> I'll check it while preparing the next iteration.
>
>>
>>> + if (IS_ERR(plane))
>>> + return plane;
>>> +
>>> + drm_plane_helper_add(plane, &dpu_plane_virtual_helper_funcs);
>>> +
>>> + DPU_DEBUG("%s created virtual id:%u\n", plane->name, plane->base.id);
>>> +
>>> return plane;
>>> }
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>>> index a3ae45dc95d0..15f7d60d8b85 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>>> @@ -30,6 +30,7 @@
>>> * @plane_fetch_bw: calculated BW per plane
>>> * @plane_clk: calculated clk per plane
>>> * @needs_dirtyfb: whether attached CRTC needs pixel data explicitly flushed
>>> + * @saved_fmt: format used by the plane's FB, saved for for virtual plane support
>>> */
>>> struct dpu_plane_state {
>>> struct drm_plane_state base;
>>> @@ -46,6 +47,8 @@ struct dpu_plane_state {
>>> u64 plane_clk;
>>> bool needs_dirtyfb;
>>> +
>>> + const struct dpu_format *saved_fmt;
>>> };
>>
>> Why is saved_fmt needed?
>>
>> The use-case which comes to my mind is lets say if we have a RGB format and
>> we need to switch to a YUV format, basically switch from DMA to ViG SSPP,
>> then yes we have to mark planes_changed as we need to switch the underlying
>> SSPP that time, but why cant we simply check that by means of a check to see
>> if the fmt is YUV and whether CSC block is present in the SSPP.
>
> Yes, correct. And vice versa, going from YUV to RGB might free the VIG
> SSPP.
>
>>
>> This will lead to dpu_crtc_reassign_planes() getting called for format
>> changes even when the new format might be available in the same SSPP.
>
> So use 'needs_vig' instead of storing the format? Sounds good to me.
>
Yes thats the idea. Basically "needs_reassignment". You could even go
from Vig to DMA if the use-case can just use DMA to save up Vig.
Also, do we really need to cache anything in the plane state to track this?
If we have a function called dpu_crtc_needs_plane_reassignment() will go
through the current plane state and the current SSPP from the global
state and see if needs reassignment.
>>
>>> #define to_dpu_plane_state(x) \
>>> @@ -75,6 +78,16 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
>>> uint32_t pipe, enum drm_plane_type type,
>>> unsigned long possible_crtcs);
>>> +/**
>>> + * dpu_plane_init_virtual - create new dpu virtualized plane
>>> + * @dev: Pointer to DRM device
>>> + * @type: Plane type - PRIMARY/OVERLAY/CURSOR
>>> + * @possible_crtcs: bitmask of crtc that can be attached to the given pipe
>>> + */
>>> +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
>>> + enum drm_plane_type type,
>>> + unsigned long possible_crtcs);
>>> +
>>> /**
>>> * dpu_plane_color_fill - enables color fill on plane
>>> * @plane: Pointer to DRM plane object
>>> @@ -91,4 +104,10 @@ void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable);
>>> static inline void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) {}
>>> #endif
>>> +int dpu_assign_plane_resources(struct dpu_global_state *global_state,
>>> + struct drm_atomic_state *state,
>>> + struct drm_crtc *crtc,
>>> + struct drm_plane_state **states,
>>> + unsigned int num_planes);
>>> +
>>> #endif /* _DPU_PLANE_H_ */
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>> index 44938ba7a2b7..7264a4d44a14 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>> @@ -694,6 +694,83 @@ int dpu_rm_reserve(
>>> return ret;
>>> }
>>> +struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
>>> + struct dpu_global_state *global_state,
>>> + struct drm_crtc *crtc,
>>> + struct dpu_rm_sspp_requirements *reqs)
>>> +{
>>> + uint32_t crtc_id = crtc->base.id;
>>> + unsigned int weight, best_weght = UINT_MAX;
>>
>> best_weight?
>
> Yes
>
>>
>>> + struct dpu_hw_sspp *hw_sspp;
>>> + unsigned long mask = 0;
>>> + int i, best_idx = -1;
>>> +
>>> + /*
>>> + * Don't take cursor feature into consideration until there is proper support for SSPP_CURSORn.
>>> + */
>>> + mask |= BIT(DPU_SSPP_CURSOR);
>>> +
>>> + if (reqs->scale)
>>> + mask |= BIT(DPU_SSPP_SCALER_RGB) |
>>> + BIT(DPU_SSPP_SCALER_QSEED2) |
>>> + BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE);
>>> +
>>> + if (reqs->yuv)
>>> + mask |= BIT(DPU_SSPP_CSC) |
>>> + BIT(DPU_SSPP_CSC_10BIT);
>>> +
>>> + if (reqs->rot90)
>>> + mask |= BIT(DPU_SSPP_INLINE_ROTATION);
>>> +
>>> + for (i = 0; i < ARRAY_SIZE(rm->hw_sspp); i++) {
>>> + if (!rm->hw_sspp[i])
>>> + continue;
>>> +
>>> + if (global_state->sspp_to_crtc_id[i])
>>> + continue;
>>> +
>>> + hw_sspp = rm->hw_sspp[i];
>>> +
>>> + /* skip incompatible planes */
>>> + if (reqs->scale && !hw_sspp->cap->sblk->scaler_blk.len)
>>> + continue;
>>> +
>>> + if (reqs->yuv && !hw_sspp->cap->sblk->csc_blk.len)
>>> + continue;
>>> +
>>> + if (reqs->rot90 && !(hw_sspp->cap->features & DPU_SSPP_INLINE_ROTATION))
>>> + continue;
>>> +
>>> + /*
>>> + * For non-yuv, non-scaled planes prefer simple (DMA or RGB)
>>> + * plane, falling back to VIG only if there are no such planes.
>>> + *
>>> + * This way we'd leave VIG sspps to be later used for YUV formats.
>>> + */
>>> + weight = hweight64(hw_sspp->cap->features & ~mask);
>>
>> This approach is assuming that ViG feature masks are more than DMA.
>> Hence the hweight of DMA SSPP's features is less than hweight of ViG SSPPs.
>>
>> Is this really true? Because there are other bits such as DMA_SDM845_MASK
>> which might increase the hweight of DMA SSPPs
>
> Which bits are present in the DMA mask, which are not present in the VIG
> mask? Also for the older platforms there are three kinds of planes: VIG,
> DMA and RGB. The selection algorithm should not require significant
> changes to support that case.
>
DMA_SDM845_MASK has DPU_SSPP_QOS_8LVL which is not there in
VIG_MSM8998_MASK afaict. But we really cannot be counting the number of
feature bits and going by that.
Hence, inherently, going by hweight is not right because whenever we add
a catalog change to add a new feature bit to SSPP, we have to come back
here and make sure this logic will not break.
>>
>> I would rather make it simpler.
>>
>> 1) if we need scaling || yuv, then we have to get only a Vig
>> 2) else, first try to get a DMA SSPP
>
> How would you distinguish between VIG and DMA?
>
the type SSPP_TYPE_VIG OR SSPP_TYPE_DMA. We also have a SSPP_TYPE_RGB so
that should address your concern about the third type of plane (Vig,
DMA, RGB).
>> 3) if (2) fails, we have to try to get a ViG SSPP.
>>
>> Lets be more explicit about the SSPP type here rather than using hweight.
>>
>>
>>> + if (weight < best_weght) {
>>> + best_weght = weight;
>>> + best_idx = i;
>>> + }
>>> + }
>>> +
>>> + if (best_idx < 0)
>>> + return NULL;
>>> +
>>> + global_state->sspp_to_crtc_id[best_idx] = crtc_id;
>>> +
>>> + return rm->hw_sspp[best_idx];
>>> +}
>>> +
>>> +void dpu_rm_release_all_sspp(struct dpu_global_state *global_state,
>>> + struct drm_crtc *crtc)
>>> +{
>>> + uint32_t crtc_id = crtc->base.id;
>>> +
>>> + _dpu_rm_clear_mapping(global_state->sspp_to_crtc_id,
>>> + ARRAY_SIZE(global_state->sspp_to_crtc_id), crtc_id);
>>> +}
>>> +
>>> int dpu_rm_get_assigned_resources(struct dpu_rm *rm,
>>> struct dpu_global_state *global_state, uint32_t enc_id,
>>> enum dpu_hw_blk_type type, struct dpu_hw_blk **blks, int blks_size)
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
>>> index e63db8ace6b9..bf9110547385 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
>>> @@ -37,6 +37,12 @@ struct dpu_rm {
>>> struct dpu_hw_blk *cdm_blk;
>>> };
>>> +struct dpu_rm_sspp_requirements {
>>> + bool yuv;
>>> + bool scale;
>>> + bool rot90;
>>> +};
>>> +
>>> /**
>>> * dpu_rm_init - Read hardware catalog and create reservation tracking objects
>>> * for all HW blocks.
>>> @@ -82,6 +88,28 @@ int dpu_rm_reserve(struct dpu_rm *rm,
>>> void dpu_rm_release(struct dpu_global_state *global_state,
>>> struct drm_encoder *enc);
>>> +/**
>>> + * dpu_rm_reserve_sspp - Reserve the required SSPP for the provided CRTC
>>> + * @rm: DPU Resource Manager handle
>>> + * @global_state: private global state
>>> + * @crtc: DRM CRTC handle
>>> + * @reqs: SSPP required features
>>> + */
>>> +struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
>>> + struct dpu_global_state *global_state,
>>> + struct drm_crtc *crtc,
>>> + struct dpu_rm_sspp_requirements *reqs);
>>> +
>>> +/**
>>> + * dpu_rm_release_all_sspp - Given the CRTC, release all SSPP
>>> + * blocks previously reserved for that use case.
>>> + * @rm: DPU Resource Manager handle
>>> + * @crtc: DRM CRTC handle
>>> + * @Return: 0 on Success otherwise -ERROR
>>> + */
>>
>> This is void so does not return anything?
>>
>>> +void dpu_rm_release_all_sspp(struct dpu_global_state *global_state,
>>> + struct drm_crtc *crtc);
>>> +
>>> /**
>>> * Get hw resources of the given type that are assigned to this encoder.
>>> */
>
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 08/13] drm/msm/dpu: add support for virtual planes
2024-06-07 19:22 ` Abhinav Kumar
@ 2024-06-07 21:10 ` Dmitry Baryshkov
2024-06-07 21:39 ` Abhinav Kumar
0 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-06-07 21:10 UTC (permalink / raw)
To: Abhinav Kumar
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On Fri, Jun 07, 2024 at 12:22:16PM -0700, Abhinav Kumar wrote:
>
>
> On 6/7/2024 12:16 AM, Dmitry Baryshkov wrote:
> > On Thu, Jun 06, 2024 at 03:21:11PM -0700, Abhinav Kumar wrote:
> > > On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> > > > Only several SSPP blocks support such features as YUV output or scaling,
> > > > thus different DRM planes have different features. Properly utilizing
> > > > all planes requires the attention of the compositor, who should
> > > > prefer simpler planes to YUV-supporting ones. Otherwise it is very easy
> > > > to end up in a situation when all featureful planes are already
> > > > allocated for simple windows, leaving no spare plane for YUV playback.
> > > >
> > > > To solve this problem make all planes virtual. Each plane is registered
> > > > as if it supports all possible features, but then at the runtime during
> > > > the atomic_check phase the driver selects backing SSPP block for each
> > > > plane.
> > > >
> > > > Note, this does not provide support for using two different SSPP blocks
> > > > for a single plane or using two rectangles of an SSPP to drive two
> > > > planes. Each plane still gets its own SSPP and can utilize either a solo
> > > > rectangle or both multirect rectangles depending on the resolution.
> > > >
> > > > Note #2: By default support for virtual planes is turned off and the
> > > > driver still uses old code path with preallocated SSPP block for each
> > > > plane. To enable virtual planes, pass 'msm.dpu_use_virtual_planes=1'
> > > > kernel parameter.
> > > >
> > >
> > > I like the overall approach in this patch. Some comments below.
> > >
> > > > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > ---
> > > > drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 50 +++++
> > > > drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 10 +-
> > > > drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 4 +
> > > > drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 230 +++++++++++++++++++---
> > > > drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 19 ++
> > > > drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 77 ++++++++
> > > > drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 28 +++
> > > > 7 files changed, 390 insertions(+), 28 deletions(-)
> > > >
> > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > index 88c2e51ab166..794c5643584f 100644
> > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > @@ -1168,6 +1168,49 @@ static bool dpu_crtc_needs_dirtyfb(struct drm_crtc_state *cstate)
> > > > return false;
> > > > }
> > > > +static int dpu_crtc_reassign_planes(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
> > > > +{
> > > > + int total_planes = crtc->dev->mode_config.num_total_plane;
> > > > + struct drm_atomic_state *state = crtc_state->state;
> > > > + struct dpu_global_state *global_state;
> > > > + struct drm_plane_state **states;
> > > > + struct drm_plane *plane;
> > > > + int ret;
> > > > +
> > > > + global_state = dpu_kms_get_global_state(crtc_state->state);
> > > > + if (IS_ERR(global_state))
> > > > + return PTR_ERR(global_state);
> > > > +
> > > > + dpu_rm_release_all_sspp(global_state, crtc);
> > > > +
> > >
> > > Do we need to call dpu_rm_release_all_sspp() even in the
> > > _dpu_plane_atomic_disable()?
> >
> > It allows the driver to optimize the usage of the SSPP rectangles.
> >
>
> No, what I meant was that we should call dpu_rm_release_all_sspp() in
> dpu_plane_atomic_update() as well because in the atomic_check() path where
> its called today, its being called only for zpos_changed and planes_changed
> but during disable we must call this for sure.
No. the dpu_rm_release_all_sspp() should only be called during check.
When dpu_plane_atomic_update() is called, the state should already be
finalised. The atomic_check() callback is called when a plane is going
to be disabled.
>
> > >
> > > > + if (!crtc_state->enable)
> > > > + return 0;
> > > > +
> > > > + states = kcalloc(total_planes, sizeof(*states), GFP_KERNEL);
> > > > + if (!states)
> > > > + return -ENOMEM;
> > > > +
> > > > + drm_atomic_crtc_state_for_each_plane(plane, crtc_state) {
> > > > + struct drm_plane_state *plane_state =
> > > > + drm_atomic_get_plane_state(state, plane);
> > > > +
> > > > + if (IS_ERR(plane_state)) {
> > > > + ret = PTR_ERR(plane_state);
> > > > + goto done;
> > > > + }
> > > > +
> > > > + states[plane_state->normalized_zpos] = plane_state;
> > > > + }
> > > > +
> > > > + ret = dpu_assign_plane_resources(global_state, state, crtc, states, total_planes);
> > > > +
> > > > +done:
> > > > + kfree(states);
> > > > + return ret;
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
> > > > struct drm_atomic_state *state)
> > > > {
> > > > @@ -1183,6 +1226,13 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
> > > > bool needs_dirtyfb = dpu_crtc_needs_dirtyfb(crtc_state);
> > > > + if (dpu_use_virtual_planes &&
> > > > + (crtc_state->planes_changed || crtc_state->zpos_changed)) {
> > >
> > > Here, I assume you are relying on DRM to set zpos_changed. But can you
> > > please elaborate why we have to reassign planes when zpos_changes?
> >
> > Because the SSPP might be split between two planes. If zpos has changed
> > we might have to break this split and use two different SSPPs for those
> > planes.
> >
>
> Got it. But that support has not been added yet so belongs to a later
> patchset?
Yes and no. This patch still fills the plane states array following the
zpos order. If the z-order changes, the result of
dpu_assign_plane_resources() might change too. The actual algorithm that
assigns SSPPs is a different code unit. So, I do not want to get back to
this code while changing the dpu_assign_plane_resources()
implementation.
>
> > >
> > > > + rc = dpu_crtc_reassign_planes(crtc, crtc_state);
> > > > + if (rc < 0)
> > > > + return rc;
> > > > + }
> > > > +
> > > > if (!crtc_state->enable || !drm_atomic_crtc_effectively_active(crtc_state)) {
> > > > DRM_DEBUG_ATOMIC("crtc%d -> enable %d, active %d, skip atomic_check\n",
> > > > crtc->base.id, crtc_state->enable,
> > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> > > > index 9a1fe6868979..becdd98f3c40 100644
> > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> > > > @@ -51,6 +51,9 @@
> > > > #define DPU_DEBUGFS_DIR "msm_dpu"
> > > > #define DPU_DEBUGFS_HWMASKNAME "hw_log_mask"
> > > > +bool dpu_use_virtual_planes = false;
> > > > +module_param(dpu_use_virtual_planes, bool, 0);
> > > > +
> > > > static int dpu_kms_hw_init(struct msm_kms *kms);
> > > > static void _dpu_kms_mmu_destroy(struct dpu_kms *dpu_kms);
> > > > @@ -770,8 +773,11 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms)
> > > > type, catalog->sspp[i].features,
> > > > catalog->sspp[i].features & BIT(DPU_SSPP_CURSOR));
> > > > - plane = dpu_plane_init(dev, catalog->sspp[i].id, type,
> > > > - (1UL << max_crtc_count) - 1);
> > > > + if (dpu_use_virtual_planes)
> > > > + plane = dpu_plane_init_virtual(dev, type, (1UL << max_crtc_count) - 1);
> > > > + else
> > > > + plane = dpu_plane_init(dev, catalog->sspp[i].id, type,
> > > > + (1UL << max_crtc_count) - 1);
> > > > if (IS_ERR(plane)) {
> > > > DPU_ERROR("dpu_plane_init failed\n");
> > > > ret = PTR_ERR(plane);
> > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
> > > > index e2adc937ea63..195257660057 100644
> > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
> > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
> > > > @@ -64,6 +64,8 @@
> > > > #define ktime_compare_safe(A, B) \
> > > > ktime_compare(ktime_sub((A), (B)), ktime_set(0, 0))
> > > > +extern bool dpu_use_virtual_planes;
> > > > +
> > > > struct dpu_kms {
> > > > struct msm_kms base;
> > > > struct drm_device *dev;
> > > > @@ -138,6 +140,8 @@ struct dpu_global_state {
> > > > uint32_t dspp_to_enc_id[DSPP_MAX - DSPP_0];
> > > > uint32_t dsc_to_enc_id[DSC_MAX - DSC_0];
> > > > uint32_t cdm_to_enc_id;
> > > > +
> > > > + uint32_t sspp_to_crtc_id[SSPP_MAX - SSPP_NONE];
> > >
> > > I will re-visit this sspp_to_crtc_id mapping after checking the rest of the
> > > patches.
> > >
> > > > };
> > > > struct dpu_global_state
> > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > index a41ffa2d774b..2961b809ccf3 100644
> > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > @@ -876,7 +876,7 @@ static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
> > > > drm_rect_rotate_inv(&pipe_cfg->src_rect,
> > > > new_plane_state->fb->width, new_plane_state->fb->height,
> > > > new_plane_state->rotation);
> > > > - if (r_pipe_cfg->src_rect.x1 != 0)
> > > > + 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);
> > > > @@ -942,7 +942,7 @@ static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
> > > > if (ret)
> > > > return ret;
> > > > - if (r_pipe_cfg->src_rect.x1 != 0) {
> > > > + if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) {
> > > > /*
> > > > * In parallel multirect case only the half of the usual width
> > > > * is supported for tiled formats. If we are here, we know that
> > > > @@ -1022,6 +1022,113 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> > > > return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
> > > > }
> > >
> > > This part should goto patch 6 right?
> >
> > Why? This is only relevant for the virtual planes.
> >
>
> Patch 6 introducted the if (r_pipe_cfg->src_rect.x1 != 0) checks from
> afaict. Was that to ensure there was a valid src_rect for the r_pipe before
> invoking drm_rect_rotate_inv()?
>
> This patch changes it from using x1!=0 to using drm_rect_width().
>
> Why cant this check be moved to that patch itself is my question.
I now understand your concern. Yes, this should (and in fact must) be
moved to that patch.
>
> > >
> > > > +static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
> > > > + struct drm_atomic_state *state)
> > > > +{
> > > > + struct drm_plane_state *plane_state =
> > > > + drm_atomic_get_plane_state(state, plane);
> > > > + struct dpu_plane_state *pstate = to_dpu_plane_state(plane_state);
> > > > + const struct dpu_format *format;
> > > > + struct drm_crtc_state *crtc_state;
> > > > + int ret;
> > > > +
> > > > + if (plane_state->crtc)
> > > > + crtc_state = drm_atomic_get_new_crtc_state(state,
> > > > + plane_state->crtc);
> > > > +
> > > > + ret = dpu_plane_atomic_check_nopipe(plane, plane_state, crtc_state);
> > > > + if (ret)
> > > > + return ret;
> > > > +
> > > > + if (!plane_state->visible) {
> > > > + /*
> > > > + * resources are freed by dpu_crtc_assign_plane_resources(),
> > > > + * but clean them here.
> > > > + */
> > > > + pstate->pipe.sspp = NULL;
> > > > + pstate->r_pipe.sspp = NULL;
> > > > +
> > > > + return 0;
> > > > + }
> > > > +
> > > > + format = to_dpu_format(msm_framebuffer_format(plane_state->fb));
> > > > +
> > > > + /* force resource reallocation if the format of FB has changed */
> > > > + if (pstate->saved_fmt != format) {
> > > > + crtc_state->planes_changed = true;
> > >
> > > planes_changed means planes on this CRTC are updated. We are using this to
> > > track that the underlying SSPP of the plane needs to be changed?
> > >
> > > Is this still correct because this might conflict with the DRM's expectation
> > > of planes_changed.
> >
> > No, it still means that the planes were changed. DRM doesn't seem to
> > care about the format changes. We do.
> >
>
> Yes, I am aware that we need to detect format changes and re-assign SSPP if
> needed if the SSPP does not support the format which was requested.
>
> My question was whether planes_changed is the right way to track that
> because that is being used by DRM to track whether the plane's CRTC changed
> so I dont know whether its appropriate to overload that meaning.
planes_changed is a hint that planes were updated. It is not limited to
just toggling the planes.
> Also from the other comment below, since we are dropping saved_fmt, do we
> need to retain planes_changed setting?
Yes. We still need to track the YUV <-> RGB-related changes.
>
> > >
> > > > + pstate->saved_fmt = format;
> > > > + }
> > > > +
> > > > + 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)
> > > > +{
> > > > + 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;
> > > > + struct dpu_sw_pipe *pipe;
> > > > + struct dpu_sw_pipe *r_pipe;
> > > > + const struct dpu_format *fmt;
> > > > +
> > > > + if (plane_state->crtc)
> > > > + crtc_state = drm_atomic_get_new_crtc_state(state,
> > > > + plane_state->crtc);
> > > > +
> > > > + pstate = to_dpu_plane_state(plane_state);
> > > > + pipe = &pstate->pipe;
> > > > + r_pipe = &pstate->r_pipe;
> > > > +
> > > > + pipe->sspp = NULL;
> > > > + r_pipe->sspp = NULL;
> > > > +
> > > > + if (!plane_state->fb)
> > > > + return -EINVAL;
> > > > +
> > > > + fmt = to_dpu_format(msm_framebuffer_format(plane_state->fb));
> > > > + reqs.yuv = DPU_FORMAT_IS_YUV(fmt);
> > > > + reqs.scale = (plane_state->src_w >> 16 != plane_state->crtc_w) ||
> > > > + (plane_state->src_h >> 16 != plane_state->crtc_h);
> > > > +
> > > > + reqs.rot90 = drm_rotation_90_or_270(plane_state->rotation);
> > > > +
> > > > + pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
> > > > + if (!pipe->sspp)
> > > > + return -ENODEV;
> > > > +
> > > > + return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
> > > > +}
> > > > +
> > > > +int dpu_assign_plane_resources(struct dpu_global_state *global_state,
> > > > + struct drm_atomic_state *state,
> > > > + struct drm_crtc *crtc,
> > > > + struct drm_plane_state **states,
> > > > + unsigned int num_planes)
> > > > +{
> > > > + unsigned int i;
> > > > + int ret;
> > > > +
> > > > + for (i = 0; i < num_planes; i++) {
> > > > + struct drm_plane_state *plane_state = states[i];
> > > > +
> > > > + if (!plane_state ||
> > > > + !plane_state->visible)
> > > > + continue;
> > > > +
> > > > + ret = dpu_plane_virtual_assign_resources(crtc, global_state,
> > > > + state, plane_state);
> > > > + if (ret)
> > > > + break;
> > > > + }
> > > > +
> > > > + return ret;
> > > > +}
> > > > +
> > > > static void dpu_plane_flush_csc(struct dpu_plane *pdpu, struct dpu_sw_pipe *pipe)
> > > > {
> > > > const struct dpu_format *format =
> > > > @@ -1342,12 +1449,14 @@ static void dpu_plane_atomic_print_state(struct drm_printer *p,
> > > > drm_printf(p, "\tstage=%d\n", pstate->stage);
> > > > - 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 (pipe->sspp) {
> > > > + 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));
> > > > + }
> > >
> > > I dont mind this being pushed out as a separate patch to protect pipe->sspp.
> > > Even though it is static assignment today, there is no harm against adding
> > > this protection even today IMO.
> >
> > No, it doesn't make sense. Currently pipe->sspp is always valid.
> > Unnecessary checks do harm, they make you think that the condition they
> > are checking might be invalid.
> >
>
> Ack.
>
> > >
> > > > if (r_pipe->sspp) {
> > > > drm_printf(p, "\tsspp[1]=%s\n", r_pipe->sspp->cap->name);
> > > > @@ -1436,31 +1545,29 @@ static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = {
> > > > .atomic_update = dpu_plane_atomic_update,
> > > > };
> > > > +static const struct drm_plane_helper_funcs dpu_plane_virtual_helper_funcs = {
> > > > + .prepare_fb = dpu_plane_prepare_fb,
> > > > + .cleanup_fb = dpu_plane_cleanup_fb,
> > > > + .atomic_check = dpu_plane_virtual_atomic_check,
> > > > + .atomic_update = dpu_plane_atomic_update,
> > > > +};
> > > > +
> > > > /* initialize plane */
> > > > -struct drm_plane *dpu_plane_init(struct drm_device *dev,
> > > > - uint32_t pipe, enum drm_plane_type type,
> > > > - unsigned long possible_crtcs)
> > > > +static struct drm_plane *dpu_plane_init_common(struct drm_device *dev,
> > > > + enum drm_plane_type type,
> > > > + unsigned long possible_crtcs,
> > > > + bool inline_rotation,
> > > > + const uint32_t *format_list,
> > > > + uint32_t num_formats,
> > > > + enum dpu_sspp pipe)
> > > > {
> > > > struct drm_plane *plane = NULL;
> > > > - const uint32_t *format_list;
> > > > struct dpu_plane *pdpu;
> > > > struct msm_drm_private *priv = dev->dev_private;
> > > > struct dpu_kms *kms = to_dpu_kms(priv->kms);
> > > > - struct dpu_hw_sspp *pipe_hw;
> > > > - uint32_t num_formats;
> > > > uint32_t supported_rotations;
> > > > int ret;
> > > > - /* initialize underlying h/w driver */
> > > > - pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);
> > > > - if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {
> > > > - DPU_ERROR("[%u]SSPP is invalid\n", pipe);
> > > > - return ERR_PTR(-EINVAL);
> > > > - }
> > > > -
> > > > - format_list = pipe_hw->cap->sblk->format_list;
> > > > - num_formats = pipe_hw->cap->sblk->num_formats;
> > > > -
> > > > pdpu = drmm_universal_plane_alloc(dev, struct dpu_plane, base,
> > > > 0xff, &dpu_plane_funcs,
> > > > format_list, num_formats,
> > > > @@ -1486,7 +1593,7 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
> > > > supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
> > > > - if (pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION))
> > > > + if (inline_rotation)
> > > > supported_rotations |= DRM_MODE_ROTATE_MASK;
> > > > drm_plane_create_rotation_property(plane,
> > > > @@ -1494,10 +1601,81 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
> > > > drm_plane_enable_fb_damage_clips(plane);
> > > > - /* success! finalize initialization */
> > > > + DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
> > > > + pipe, plane->base.id);
> > > > + return plane;
> > > > +}
> > > > +
> > > > +struct drm_plane *dpu_plane_init(struct drm_device *dev,
> > > > + uint32_t pipe, enum drm_plane_type type,
> > > > + unsigned long possible_crtcs)
> > > > +{
> > > > + struct drm_plane *plane = NULL;
> > > > + struct msm_drm_private *priv = dev->dev_private;
> > > > + struct dpu_kms *kms = to_dpu_kms(priv->kms);
> > > > + struct dpu_hw_sspp *pipe_hw;
> > > > +
> > > > + /* initialize underlying h/w driver */
> > > > + pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);
> > > > + if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {
> > > > + DPU_ERROR("[%u]SSPP is invalid\n", pipe);
> > > > + return ERR_PTR(-EINVAL);
> > > > + }
> > > > +
> > > > +
> > > > + plane = dpu_plane_init_common(dev, type, possible_crtcs,
> > > > + pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION),
> > > > + pipe_hw->cap->sblk->format_list,
> > > > + pipe_hw->cap->sblk->num_formats,
> > > > + pipe);
> > > > + if (IS_ERR(plane))
> > > > + return plane;
> > > > +
> > > > drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
> > > > DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
> > > > pipe, plane->base.id);
> > > > +
> > > > + return plane;
> > > > +}
> > > > +
> > > > +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
> > > > + enum drm_plane_type type,
> > > > + unsigned long possible_crtcs)
> > > > +{
> > > > + struct drm_plane *plane = NULL;
> > > > + struct msm_drm_private *priv = dev->dev_private;
> > > > + struct dpu_kms *kms = to_dpu_kms(priv->kms);
> > > > + bool has_inline_rotation = false;
> > > > + const u32 *format_list = NULL;
> > > > + u32 num_formats = 0;
> > > > + int i;
> > > > +
> > > > + /* Determine the largest configuration that we can implement */
> > > > + for (i = 0; i < kms->catalog->sspp_count; i++) {
> > > > + const struct dpu_sspp_cfg *cfg = &kms->catalog->sspp[i];
> > > > +
> > > > + if (test_bit(DPU_SSPP_INLINE_ROTATION, &cfg->features))
> > > > + has_inline_rotation = true;
> > > > +
> > > > + if (!format_list ||
> > > > + cfg->sblk->csc_blk.len) {
> > >
> > > But format_list is being assigned to NULL just a few lines above. Why is
> > > this check needed?
> >
> > It was assigned before the loop.
> >
>
> Yes, I got this part but missed on why we needed the loop at all.
Which set of formats should the virtual plane use?
> > >
> > > I dont get why this part can also goto dpu_plane_init_common() as it looks
> > > identical to me.
> >
> > And it is not. For the non-virtual case there is no loop around formats
> > list assignment.
> >
>
> Ah okay, I misunderstood the logic. After reading the comment above the loop
> I get what you are trying to do here.
>
> But I dont get why you really need to do that?
>
> 1) In this patch the relationship between virtual plane and SSPP is still
> 1:1 so what is wrong to retain the sspp's actual format for the plane rather
> than picking the best format (you are targetting Vig SSPP)
No. With this patch there is no 1:1 relationship. The RM will select the
SSPP that suits the requirements (YUV, scaling, rotation, etc).
> In fact, that will reduce atomic_check() failures with this patch because
> compositor will still work the same way as it used to work before by not
> trying an unsupported format on a plane.
The virtual plane should support any of the formats that the backing
hardware can support. If (for example) we only had RGB-only and YUV-only
hardware blocks, the driver would have to construct a _superset_ of
those formats. Fortunately this is not the case and VIG supports a
strict superset of what DMA (or RGB) SSPP supports.
> If one plane maps to two SSPPs, then yes we can go with the superset of
> formats but that comes in a later patch right?
>
> 2) So even if we want to do it this way from this patch itself, I think all
> you are looking for is whether there is a Vig SSPP and if so use
> plane_formats_yuv. There is no need for this loop IMO.
>
> 3) I noticed that virt_format_list is still present in the driver. If you
> are planning to not use that perhaps drop it with this series.
Ack
>
> > >
> > >
> > > > + format_list = cfg->sblk->format_list;
> > > > + num_formats = cfg->sblk->num_formats;
> > > > + }
> > > > + }
> > > > +
> > > > + plane = dpu_plane_init_common(dev, type, possible_crtcs,
> > > > + has_inline_rotation,
> > > > + format_list,
> > > > + num_formats,
> > > > + SSPP_NONE);
> > >
> > > Ok, here is the part which we were discussing in
> > >
> > > https://patchwork.freedesktop.org/patch/582820/?series=131109&rev=1#comment_1087370
> > >
> > > So yes, that part belongs to this patch.
> >
> > I'll check it while preparing the next iteration.
> >
> > >
> > > > + if (IS_ERR(plane))
> > > > + return plane;
> > > > +
> > > > + drm_plane_helper_add(plane, &dpu_plane_virtual_helper_funcs);
> > > > +
> > > > + DPU_DEBUG("%s created virtual id:%u\n", plane->name, plane->base.id);
> > > > +
> > > > return plane;
> > > > }
> > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> > > > index a3ae45dc95d0..15f7d60d8b85 100644
> > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> > > > @@ -30,6 +30,7 @@
> > > > * @plane_fetch_bw: calculated BW per plane
> > > > * @plane_clk: calculated clk per plane
> > > > * @needs_dirtyfb: whether attached CRTC needs pixel data explicitly flushed
> > > > + * @saved_fmt: format used by the plane's FB, saved for for virtual plane support
> > > > */
> > > > struct dpu_plane_state {
> > > > struct drm_plane_state base;
> > > > @@ -46,6 +47,8 @@ struct dpu_plane_state {
> > > > u64 plane_clk;
> > > > bool needs_dirtyfb;
> > > > +
> > > > + const struct dpu_format *saved_fmt;
> > > > };
> > >
> > > Why is saved_fmt needed?
> > >
> > > The use-case which comes to my mind is lets say if we have a RGB format and
> > > we need to switch to a YUV format, basically switch from DMA to ViG SSPP,
> > > then yes we have to mark planes_changed as we need to switch the underlying
> > > SSPP that time, but why cant we simply check that by means of a check to see
> > > if the fmt is YUV and whether CSC block is present in the SSPP.
> >
> > Yes, correct. And vice versa, going from YUV to RGB might free the VIG
> > SSPP.
> >
> > >
> > > This will lead to dpu_crtc_reassign_planes() getting called for format
> > > changes even when the new format might be available in the same SSPP.
> >
> > So use 'needs_vig' instead of storing the format? Sounds good to me.
> >
>
> Yes thats the idea. Basically "needs_reassignment". You could even go from
> Vig to DMA if the use-case can just use DMA to save up Vig.
>
> Also, do we really need to cache anything in the plane state to track this?
>
> If we have a function called dpu_crtc_needs_plane_reassignment() will go
> through the current plane state and the current SSPP from the global state
> and see if needs reassignment.
No, looking at the global state won't be possible here. I'd have to lock
the private object before consulting it, which might cause EDEADLOCK
later on during resource reallocation. So all necessary information
should be stored in the dpu_plane_state.
>
> > >
> > > > #define to_dpu_plane_state(x) \
> > > > @@ -75,6 +78,16 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
> > > > uint32_t pipe, enum drm_plane_type type,
> > > > unsigned long possible_crtcs);
> > > > +/**
> > > > + * dpu_plane_init_virtual - create new dpu virtualized plane
> > > > + * @dev: Pointer to DRM device
> > > > + * @type: Plane type - PRIMARY/OVERLAY/CURSOR
> > > > + * @possible_crtcs: bitmask of crtc that can be attached to the given pipe
> > > > + */
> > > > +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
> > > > + enum drm_plane_type type,
> > > > + unsigned long possible_crtcs);
> > > > +
> > > > /**
> > > > * dpu_plane_color_fill - enables color fill on plane
> > > > * @plane: Pointer to DRM plane object
> > > > @@ -91,4 +104,10 @@ void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable);
> > > > static inline void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) {}
> > > > #endif
> > > > +int dpu_assign_plane_resources(struct dpu_global_state *global_state,
> > > > + struct drm_atomic_state *state,
> > > > + struct drm_crtc *crtc,
> > > > + struct drm_plane_state **states,
> > > > + unsigned int num_planes);
> > > > +
> > > > #endif /* _DPU_PLANE_H_ */
> > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> > > > index 44938ba7a2b7..7264a4d44a14 100644
> > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> > > > @@ -694,6 +694,83 @@ int dpu_rm_reserve(
> > > > return ret;
> > > > }
> > > > +struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
> > > > + struct dpu_global_state *global_state,
> > > > + struct drm_crtc *crtc,
> > > > + struct dpu_rm_sspp_requirements *reqs)
> > > > +{
> > > > + uint32_t crtc_id = crtc->base.id;
> > > > + unsigned int weight, best_weght = UINT_MAX;
> > >
> > > best_weight?
> >
> > Yes
> >
> > >
> > > > + struct dpu_hw_sspp *hw_sspp;
> > > > + unsigned long mask = 0;
> > > > + int i, best_idx = -1;
> > > > +
> > > > + /*
> > > > + * Don't take cursor feature into consideration until there is proper support for SSPP_CURSORn.
> > > > + */
> > > > + mask |= BIT(DPU_SSPP_CURSOR);
> > > > +
> > > > + if (reqs->scale)
> > > > + mask |= BIT(DPU_SSPP_SCALER_RGB) |
> > > > + BIT(DPU_SSPP_SCALER_QSEED2) |
> > > > + BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE);
> > > > +
> > > > + if (reqs->yuv)
> > > > + mask |= BIT(DPU_SSPP_CSC) |
> > > > + BIT(DPU_SSPP_CSC_10BIT);
> > > > +
> > > > + if (reqs->rot90)
> > > > + mask |= BIT(DPU_SSPP_INLINE_ROTATION);
> > > > +
> > > > + for (i = 0; i < ARRAY_SIZE(rm->hw_sspp); i++) {
> > > > + if (!rm->hw_sspp[i])
> > > > + continue;
> > > > +
> > > > + if (global_state->sspp_to_crtc_id[i])
> > > > + continue;
> > > > +
> > > > + hw_sspp = rm->hw_sspp[i];
> > > > +
> > > > + /* skip incompatible planes */
> > > > + if (reqs->scale && !hw_sspp->cap->sblk->scaler_blk.len)
> > > > + continue;
> > > > +
> > > > + if (reqs->yuv && !hw_sspp->cap->sblk->csc_blk.len)
> > > > + continue;
> > > > +
> > > > + if (reqs->rot90 && !(hw_sspp->cap->features & DPU_SSPP_INLINE_ROTATION))
> > > > + continue;
> > > > +
> > > > + /*
> > > > + * For non-yuv, non-scaled planes prefer simple (DMA or RGB)
> > > > + * plane, falling back to VIG only if there are no such planes.
> > > > + *
> > > > + * This way we'd leave VIG sspps to be later used for YUV formats.
> > > > + */
> > > > + weight = hweight64(hw_sspp->cap->features & ~mask);
> > >
> > > This approach is assuming that ViG feature masks are more than DMA.
> > > Hence the hweight of DMA SSPP's features is less than hweight of ViG SSPPs.
> > >
> > > Is this really true? Because there are other bits such as DMA_SDM845_MASK
> > > which might increase the hweight of DMA SSPPs
> >
> > Which bits are present in the DMA mask, which are not present in the VIG
> > mask? Also for the older platforms there are three kinds of planes: VIG,
> > DMA and RGB. The selection algorithm should not require significant
> > changes to support that case.
> >
>
> DMA_SDM845_MASK has DPU_SSPP_QOS_8LVL which is not there in VIG_MSM8998_MASK
> afaict. But we really cannot be counting the number of feature bits and
> going by that.
MSM8998 uses DMA_MSM8998_MASK, not DMA_SDM845_MASK.
> Hence, inherently, going by hweight is not right because whenever we add a
> catalog change to add a new feature bit to SSPP, we have to come back here
> and make sure this logic will not break.
> > >
> > > I would rather make it simpler.
> > >
> > > 1) if we need scaling || yuv, then we have to get only a Vig
> > > 2) else, first try to get a DMA SSPP
> >
> > How would you distinguish between VIG and DMA?
> >
>
> the type SSPP_TYPE_VIG OR SSPP_TYPE_DMA. We also have a SSPP_TYPE_RGB so
> that should address your concern about the third type of plane (Vig, DMA,
> RGB).
I don't particularly like the idea of using type. We still need to
evaluate plane's features. Consider QCM2290, where VIG planes do not
support scaling.
I will evaluate if I can rework this part to use type, while still
checking for the feature bit. BTW: should we prefer RGB or DMA plane if
all other conditions are met?
>
>
> > > 3) if (2) fails, we have to try to get a ViG SSPP.
> > >
> > > Lets be more explicit about the SSPP type here rather than using hweight.
> > >
> > >
> > > > + if (weight < best_weght) {
> > > > + best_weght = weight;
> > > > + best_idx = i;
> > > > + }
> > > > + }
> > > > +
> > > > + if (best_idx < 0)
> > > > + return NULL;
> > > > +
> > > > + global_state->sspp_to_crtc_id[best_idx] = crtc_id;
> > > > +
> > > > + return rm->hw_sspp[best_idx];
> > > > +}
> > > > +
> > > > +void dpu_rm_release_all_sspp(struct dpu_global_state *global_state,
> > > > + struct drm_crtc *crtc)
> > > > +{
> > > > + uint32_t crtc_id = crtc->base.id;
> > > > +
> > > > + _dpu_rm_clear_mapping(global_state->sspp_to_crtc_id,
> > > > + ARRAY_SIZE(global_state->sspp_to_crtc_id), crtc_id);
> > > > +}
> > > > +
> > > > int dpu_rm_get_assigned_resources(struct dpu_rm *rm,
> > > > struct dpu_global_state *global_state, uint32_t enc_id,
> > > > enum dpu_hw_blk_type type, struct dpu_hw_blk **blks, int blks_size)
> > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> > > > index e63db8ace6b9..bf9110547385 100644
> > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> > > > @@ -37,6 +37,12 @@ struct dpu_rm {
> > > > struct dpu_hw_blk *cdm_blk;
> > > > };
> > > > +struct dpu_rm_sspp_requirements {
> > > > + bool yuv;
> > > > + bool scale;
> > > > + bool rot90;
> > > > +};
> > > > +
> > > > /**
> > > > * dpu_rm_init - Read hardware catalog and create reservation tracking objects
> > > > * for all HW blocks.
> > > > @@ -82,6 +88,28 @@ int dpu_rm_reserve(struct dpu_rm *rm,
> > > > void dpu_rm_release(struct dpu_global_state *global_state,
> > > > struct drm_encoder *enc);
> > > > +/**
> > > > + * dpu_rm_reserve_sspp - Reserve the required SSPP for the provided CRTC
> > > > + * @rm: DPU Resource Manager handle
> > > > + * @global_state: private global state
> > > > + * @crtc: DRM CRTC handle
> > > > + * @reqs: SSPP required features
> > > > + */
> > > > +struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
> > > > + struct dpu_global_state *global_state,
> > > > + struct drm_crtc *crtc,
> > > > + struct dpu_rm_sspp_requirements *reqs);
> > > > +
> > > > +/**
> > > > + * dpu_rm_release_all_sspp - Given the CRTC, release all SSPP
> > > > + * blocks previously reserved for that use case.
> > > > + * @rm: DPU Resource Manager handle
> > > > + * @crtc: DRM CRTC handle
> > > > + * @Return: 0 on Success otherwise -ERROR
> > > > + */
> > >
> > > This is void so does not return anything?
Yes
> > >
> > > > +void dpu_rm_release_all_sspp(struct dpu_global_state *global_state,
> > > > + struct drm_crtc *crtc);
> > > > +
> > > > /**
> > > > * Get hw resources of the given type that are assigned to this encoder.
> > > > */
> >
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 08/13] drm/msm/dpu: add support for virtual planes
2024-06-07 21:10 ` Dmitry Baryshkov
@ 2024-06-07 21:39 ` Abhinav Kumar
2024-06-07 22:26 ` Dmitry Baryshkov
0 siblings, 1 reply; 50+ messages in thread
From: Abhinav Kumar @ 2024-06-07 21:39 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On 6/7/2024 2:10 PM, Dmitry Baryshkov wrote:
> On Fri, Jun 07, 2024 at 12:22:16PM -0700, Abhinav Kumar wrote:
>>
>>
>> On 6/7/2024 12:16 AM, Dmitry Baryshkov wrote:
>>> On Thu, Jun 06, 2024 at 03:21:11PM -0700, Abhinav Kumar wrote:
>>>> On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
>>>>> Only several SSPP blocks support such features as YUV output or scaling,
>>>>> thus different DRM planes have different features. Properly utilizing
>>>>> all planes requires the attention of the compositor, who should
>>>>> prefer simpler planes to YUV-supporting ones. Otherwise it is very easy
>>>>> to end up in a situation when all featureful planes are already
>>>>> allocated for simple windows, leaving no spare plane for YUV playback.
>>>>>
>>>>> To solve this problem make all planes virtual. Each plane is registered
>>>>> as if it supports all possible features, but then at the runtime during
>>>>> the atomic_check phase the driver selects backing SSPP block for each
>>>>> plane.
>>>>>
>>>>> Note, this does not provide support for using two different SSPP blocks
>>>>> for a single plane or using two rectangles of an SSPP to drive two
>>>>> planes. Each plane still gets its own SSPP and can utilize either a solo
>>>>> rectangle or both multirect rectangles depending on the resolution.
>>>>>
>>>>> Note #2: By default support for virtual planes is turned off and the
>>>>> driver still uses old code path with preallocated SSPP block for each
>>>>> plane. To enable virtual planes, pass 'msm.dpu_use_virtual_planes=1'
>>>>> kernel parameter.
>>>>>
>>>>
>>>> I like the overall approach in this patch. Some comments below.
>>>>
>>>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>>>> ---
>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 50 +++++
>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 10 +-
>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 4 +
>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 230 +++++++++++++++++++---
>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 19 ++
>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 77 ++++++++
>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 28 +++
>>>>> 7 files changed, 390 insertions(+), 28 deletions(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>> index 88c2e51ab166..794c5643584f 100644
>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>> @@ -1168,6 +1168,49 @@ static bool dpu_crtc_needs_dirtyfb(struct drm_crtc_state *cstate)
>>>>> return false;
>>>>> }
>>>>> +static int dpu_crtc_reassign_planes(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
>>>>> +{
>>>>> + int total_planes = crtc->dev->mode_config.num_total_plane;
>>>>> + struct drm_atomic_state *state = crtc_state->state;
>>>>> + struct dpu_global_state *global_state;
>>>>> + struct drm_plane_state **states;
>>>>> + struct drm_plane *plane;
>>>>> + int ret;
>>>>> +
>>>>> + global_state = dpu_kms_get_global_state(crtc_state->state);
>>>>> + if (IS_ERR(global_state))
>>>>> + return PTR_ERR(global_state);
>>>>> +
>>>>> + dpu_rm_release_all_sspp(global_state, crtc);
>>>>> +
>>>>
>>>> Do we need to call dpu_rm_release_all_sspp() even in the
>>>> _dpu_plane_atomic_disable()?
>>>
>>> It allows the driver to optimize the usage of the SSPP rectangles.
>>>
>>
>> No, what I meant was that we should call dpu_rm_release_all_sspp() in
>> dpu_plane_atomic_update() as well because in the atomic_check() path where
>> its called today, its being called only for zpos_changed and planes_changed
>> but during disable we must call this for sure.
>
> No. the dpu_rm_release_all_sspp() should only be called during check.
> When dpu_plane_atomic_update() is called, the state should already be
> finalised. The atomic_check() callback is called when a plane is going
> to be disabled.
>
atomic_check() will be called when plane is disabled but
dpu_rm_release_all_sspp() may not be called as it is protected by
zpos_changed and planes_changed. OR you need to add a !visible check
here to call dpu_rm_release_all_sspp() that time. Thats whay I wrote
previously.
>>
>>>>
>>>>> + if (!crtc_state->enable)
>>>>> + return 0;
>>>>> +
>>>>> + states = kcalloc(total_planes, sizeof(*states), GFP_KERNEL);
>>>>> + if (!states)
>>>>> + return -ENOMEM;
>>>>> +
>>>>> + drm_atomic_crtc_state_for_each_plane(plane, crtc_state) {
>>>>> + struct drm_plane_state *plane_state =
>>>>> + drm_atomic_get_plane_state(state, plane);
>>>>> +
>>>>> + if (IS_ERR(plane_state)) {
>>>>> + ret = PTR_ERR(plane_state);
>>>>> + goto done;
>>>>> + }
>>>>> +
>>>>> + states[plane_state->normalized_zpos] = plane_state;
>>>>> + }
>>>>> +
>>>>> + ret = dpu_assign_plane_resources(global_state, state, crtc, states, total_planes);
>>>>> +
>>>>> +done:
>>>>> + kfree(states);
>>>>> + return ret;
>>>>> +
>>>>> + return 0;
>>>>> +}
>>>>> +
>>>>> static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
>>>>> struct drm_atomic_state *state)
>>>>> {
>>>>> @@ -1183,6 +1226,13 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
>>>>> bool needs_dirtyfb = dpu_crtc_needs_dirtyfb(crtc_state);
>>>>> + if (dpu_use_virtual_planes &&
>>>>> + (crtc_state->planes_changed || crtc_state->zpos_changed)) {
>>>>
>>>> Here, I assume you are relying on DRM to set zpos_changed. But can you
>>>> please elaborate why we have to reassign planes when zpos_changes?
>>>
>>> Because the SSPP might be split between two planes. If zpos has changed
>>> we might have to break this split and use two different SSPPs for those
>>> planes.
>>>
>>
>> Got it. But that support has not been added yet so belongs to a later
>> patchset?
>
> Yes and no. This patch still fills the plane states array following the
> zpos order. If the z-order changes, the result of
> dpu_assign_plane_resources() might change too. The actual algorithm that
> assigns SSPPs is a different code unit. So, I do not want to get back to
> this code while changing the dpu_assign_plane_resources()
> implementation.
>
Not entirely convinced but lets see.
>>
>>>>
>>>>> + rc = dpu_crtc_reassign_planes(crtc, crtc_state);
>>>>> + if (rc < 0)
>>>>> + return rc;
>>>>> + }
>>>>> +
>>>>> if (!crtc_state->enable || !drm_atomic_crtc_effectively_active(crtc_state)) {
>>>>> DRM_DEBUG_ATOMIC("crtc%d -> enable %d, active %d, skip atomic_check\n",
>>>>> crtc->base.id, crtc_state->enable,
>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>>>>> index 9a1fe6868979..becdd98f3c40 100644
>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>>>>> @@ -51,6 +51,9 @@
>>>>> #define DPU_DEBUGFS_DIR "msm_dpu"
>>>>> #define DPU_DEBUGFS_HWMASKNAME "hw_log_mask"
>>>>> +bool dpu_use_virtual_planes = false;
>>>>> +module_param(dpu_use_virtual_planes, bool, 0);
>>>>> +
>>>>> static int dpu_kms_hw_init(struct msm_kms *kms);
>>>>> static void _dpu_kms_mmu_destroy(struct dpu_kms *dpu_kms);
>>>>> @@ -770,8 +773,11 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms)
>>>>> type, catalog->sspp[i].features,
>>>>> catalog->sspp[i].features & BIT(DPU_SSPP_CURSOR));
>>>>> - plane = dpu_plane_init(dev, catalog->sspp[i].id, type,
>>>>> - (1UL << max_crtc_count) - 1);
>>>>> + if (dpu_use_virtual_planes)
>>>>> + plane = dpu_plane_init_virtual(dev, type, (1UL << max_crtc_count) - 1);
>>>>> + else
>>>>> + plane = dpu_plane_init(dev, catalog->sspp[i].id, type,
>>>>> + (1UL << max_crtc_count) - 1);
>>>>> if (IS_ERR(plane)) {
>>>>> DPU_ERROR("dpu_plane_init failed\n");
>>>>> ret = PTR_ERR(plane);
>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
>>>>> index e2adc937ea63..195257660057 100644
>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
>>>>> @@ -64,6 +64,8 @@
>>>>> #define ktime_compare_safe(A, B) \
>>>>> ktime_compare(ktime_sub((A), (B)), ktime_set(0, 0))
>>>>> +extern bool dpu_use_virtual_planes;
>>>>> +
>>>>> struct dpu_kms {
>>>>> struct msm_kms base;
>>>>> struct drm_device *dev;
>>>>> @@ -138,6 +140,8 @@ struct dpu_global_state {
>>>>> uint32_t dspp_to_enc_id[DSPP_MAX - DSPP_0];
>>>>> uint32_t dsc_to_enc_id[DSC_MAX - DSC_0];
>>>>> uint32_t cdm_to_enc_id;
>>>>> +
>>>>> + uint32_t sspp_to_crtc_id[SSPP_MAX - SSPP_NONE];
>>>>
>>>> I will re-visit this sspp_to_crtc_id mapping after checking the rest of the
>>>> patches.
>>>>
>>>>> };
>>>>> struct dpu_global_state
>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>>>> index a41ffa2d774b..2961b809ccf3 100644
>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>>>> @@ -876,7 +876,7 @@ static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
>>>>> drm_rect_rotate_inv(&pipe_cfg->src_rect,
>>>>> new_plane_state->fb->width, new_plane_state->fb->height,
>>>>> new_plane_state->rotation);
>>>>> - if (r_pipe_cfg->src_rect.x1 != 0)
>>>>> + 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);
>>>>> @@ -942,7 +942,7 @@ static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
>>>>> if (ret)
>>>>> return ret;
>>>>> - if (r_pipe_cfg->src_rect.x1 != 0) {
>>>>> + if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) {
>>>>> /*
>>>>> * In parallel multirect case only the half of the usual width
>>>>> * is supported for tiled formats. If we are here, we know that
>>>>> @@ -1022,6 +1022,113 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
>>>>> return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
>>>>> }
>>>>
>>>> This part should goto patch 6 right?
>>>
>>> Why? This is only relevant for the virtual planes.
>>>
>>
>> Patch 6 introducted the if (r_pipe_cfg->src_rect.x1 != 0) checks from
>> afaict. Was that to ensure there was a valid src_rect for the r_pipe before
>> invoking drm_rect_rotate_inv()?
>>
>> This patch changes it from using x1!=0 to using drm_rect_width().
>>
>> Why cant this check be moved to that patch itself is my question.
>
> I now understand your concern. Yes, this should (and in fact must) be
> moved to that patch.
>
>>
>>>>
>>>>> +static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
>>>>> + struct drm_atomic_state *state)
>>>>> +{
>>>>> + struct drm_plane_state *plane_state =
>>>>> + drm_atomic_get_plane_state(state, plane);
>>>>> + struct dpu_plane_state *pstate = to_dpu_plane_state(plane_state);
>>>>> + const struct dpu_format *format;
>>>>> + struct drm_crtc_state *crtc_state;
>>>>> + int ret;
>>>>> +
>>>>> + if (plane_state->crtc)
>>>>> + crtc_state = drm_atomic_get_new_crtc_state(state,
>>>>> + plane_state->crtc);
>>>>> +
>>>>> + ret = dpu_plane_atomic_check_nopipe(plane, plane_state, crtc_state);
>>>>> + if (ret)
>>>>> + return ret;
>>>>> +
>>>>> + if (!plane_state->visible) {
>>>>> + /*
>>>>> + * resources are freed by dpu_crtc_assign_plane_resources(),
>>>>> + * but clean them here.
>>>>> + */
>>>>> + pstate->pipe.sspp = NULL;
>>>>> + pstate->r_pipe.sspp = NULL;
>>>>> +
>>>>> + return 0;
>>>>> + }
>>>>> +
>>>>> + format = to_dpu_format(msm_framebuffer_format(plane_state->fb));
>>>>> +
>>>>> + /* force resource reallocation if the format of FB has changed */
>>>>> + if (pstate->saved_fmt != format) {
>>>>> + crtc_state->planes_changed = true;
>>>>
>>>> planes_changed means planes on this CRTC are updated. We are using this to
>>>> track that the underlying SSPP of the plane needs to be changed?
>>>>
>>>> Is this still correct because this might conflict with the DRM's expectation
>>>> of planes_changed.
>>>
>>> No, it still means that the planes were changed. DRM doesn't seem to
>>> care about the format changes. We do.
>>>
>>
>> Yes, I am aware that we need to detect format changes and re-assign SSPP if
>> needed if the SSPP does not support the format which was requested.
>>
>> My question was whether planes_changed is the right way to track that
>> because that is being used by DRM to track whether the plane's CRTC changed
>> so I dont know whether its appropriate to overload that meaning.
>
> planes_changed is a hint that planes were updated. It is not limited to
> just toggling the planes.
>
>> Also from the other comment below, since we are dropping saved_fmt, do we
>> need to retain planes_changed setting?
>
> Yes. We still need to track the YUV <-> RGB-related changes.
>
Ok, got it.
>>
>>>>
>>>>> + pstate->saved_fmt = format;
>>>>> + }
>>>>> +
>>>>> + 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)
>>>>> +{
>>>>> + 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;
>>>>> + struct dpu_sw_pipe *pipe;
>>>>> + struct dpu_sw_pipe *r_pipe;
>>>>> + const struct dpu_format *fmt;
>>>>> +
>>>>> + if (plane_state->crtc)
>>>>> + crtc_state = drm_atomic_get_new_crtc_state(state,
>>>>> + plane_state->crtc);
>>>>> +
>>>>> + pstate = to_dpu_plane_state(plane_state);
>>>>> + pipe = &pstate->pipe;
>>>>> + r_pipe = &pstate->r_pipe;
>>>>> +
>>>>> + pipe->sspp = NULL;
>>>>> + r_pipe->sspp = NULL;
>>>>> +
>>>>> + if (!plane_state->fb)
>>>>> + return -EINVAL;
>>>>> +
>>>>> + fmt = to_dpu_format(msm_framebuffer_format(plane_state->fb));
>>>>> + reqs.yuv = DPU_FORMAT_IS_YUV(fmt);
>>>>> + reqs.scale = (plane_state->src_w >> 16 != plane_state->crtc_w) ||
>>>>> + (plane_state->src_h >> 16 != plane_state->crtc_h);
>>>>> +
>>>>> + reqs.rot90 = drm_rotation_90_or_270(plane_state->rotation);
>>>>> +
>>>>> + pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
>>>>> + if (!pipe->sspp)
>>>>> + return -ENODEV;
>>>>> +
>>>>> + return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
>>>>> +}
>>>>> +
>>>>> +int dpu_assign_plane_resources(struct dpu_global_state *global_state,
>>>>> + struct drm_atomic_state *state,
>>>>> + struct drm_crtc *crtc,
>>>>> + struct drm_plane_state **states,
>>>>> + unsigned int num_planes)
>>>>> +{
>>>>> + unsigned int i;
>>>>> + int ret;
>>>>> +
>>>>> + for (i = 0; i < num_planes; i++) {
>>>>> + struct drm_plane_state *plane_state = states[i];
>>>>> +
>>>>> + if (!plane_state ||
>>>>> + !plane_state->visible)
>>>>> + continue;
>>>>> +
>>>>> + ret = dpu_plane_virtual_assign_resources(crtc, global_state,
>>>>> + state, plane_state);
>>>>> + if (ret)
>>>>> + break;
>>>>> + }
>>>>> +
>>>>> + return ret;
>>>>> +}
>>>>> +
>>>>> static void dpu_plane_flush_csc(struct dpu_plane *pdpu, struct dpu_sw_pipe *pipe)
>>>>> {
>>>>> const struct dpu_format *format =
>>>>> @@ -1342,12 +1449,14 @@ static void dpu_plane_atomic_print_state(struct drm_printer *p,
>>>>> drm_printf(p, "\tstage=%d\n", pstate->stage);
>>>>> - 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 (pipe->sspp) {
>>>>> + 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));
>>>>> + }
>>>>
>>>> I dont mind this being pushed out as a separate patch to protect pipe->sspp.
>>>> Even though it is static assignment today, there is no harm against adding
>>>> this protection even today IMO.
>>>
>>> No, it doesn't make sense. Currently pipe->sspp is always valid.
>>> Unnecessary checks do harm, they make you think that the condition they
>>> are checking might be invalid.
>>>
>>
>> Ack.
>>
>>>>
>>>>> if (r_pipe->sspp) {
>>>>> drm_printf(p, "\tsspp[1]=%s\n", r_pipe->sspp->cap->name);
>>>>> @@ -1436,31 +1545,29 @@ static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = {
>>>>> .atomic_update = dpu_plane_atomic_update,
>>>>> };
>>>>> +static const struct drm_plane_helper_funcs dpu_plane_virtual_helper_funcs = {
>>>>> + .prepare_fb = dpu_plane_prepare_fb,
>>>>> + .cleanup_fb = dpu_plane_cleanup_fb,
>>>>> + .atomic_check = dpu_plane_virtual_atomic_check,
>>>>> + .atomic_update = dpu_plane_atomic_update,
>>>>> +};
>>>>> +
>>>>> /* initialize plane */
>>>>> -struct drm_plane *dpu_plane_init(struct drm_device *dev,
>>>>> - uint32_t pipe, enum drm_plane_type type,
>>>>> - unsigned long possible_crtcs)
>>>>> +static struct drm_plane *dpu_plane_init_common(struct drm_device *dev,
>>>>> + enum drm_plane_type type,
>>>>> + unsigned long possible_crtcs,
>>>>> + bool inline_rotation,
>>>>> + const uint32_t *format_list,
>>>>> + uint32_t num_formats,
>>>>> + enum dpu_sspp pipe)
>>>>> {
>>>>> struct drm_plane *plane = NULL;
>>>>> - const uint32_t *format_list;
>>>>> struct dpu_plane *pdpu;
>>>>> struct msm_drm_private *priv = dev->dev_private;
>>>>> struct dpu_kms *kms = to_dpu_kms(priv->kms);
>>>>> - struct dpu_hw_sspp *pipe_hw;
>>>>> - uint32_t num_formats;
>>>>> uint32_t supported_rotations;
>>>>> int ret;
>>>>> - /* initialize underlying h/w driver */
>>>>> - pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);
>>>>> - if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {
>>>>> - DPU_ERROR("[%u]SSPP is invalid\n", pipe);
>>>>> - return ERR_PTR(-EINVAL);
>>>>> - }
>>>>> -
>>>>> - format_list = pipe_hw->cap->sblk->format_list;
>>>>> - num_formats = pipe_hw->cap->sblk->num_formats;
>>>>> -
>>>>> pdpu = drmm_universal_plane_alloc(dev, struct dpu_plane, base,
>>>>> 0xff, &dpu_plane_funcs,
>>>>> format_list, num_formats,
>>>>> @@ -1486,7 +1593,7 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
>>>>> supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
>>>>> - if (pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION))
>>>>> + if (inline_rotation)
>>>>> supported_rotations |= DRM_MODE_ROTATE_MASK;
>>>>> drm_plane_create_rotation_property(plane,
>>>>> @@ -1494,10 +1601,81 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
>>>>> drm_plane_enable_fb_damage_clips(plane);
>>>>> - /* success! finalize initialization */
>>>>> + DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
>>>>> + pipe, plane->base.id);
>>>>> + return plane;
>>>>> +}
>>>>> +
>>>>> +struct drm_plane *dpu_plane_init(struct drm_device *dev,
>>>>> + uint32_t pipe, enum drm_plane_type type,
>>>>> + unsigned long possible_crtcs)
>>>>> +{
>>>>> + struct drm_plane *plane = NULL;
>>>>> + struct msm_drm_private *priv = dev->dev_private;
>>>>> + struct dpu_kms *kms = to_dpu_kms(priv->kms);
>>>>> + struct dpu_hw_sspp *pipe_hw;
>>>>> +
>>>>> + /* initialize underlying h/w driver */
>>>>> + pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);
>>>>> + if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {
>>>>> + DPU_ERROR("[%u]SSPP is invalid\n", pipe);
>>>>> + return ERR_PTR(-EINVAL);
>>>>> + }
>>>>> +
>>>>> +
>>>>> + plane = dpu_plane_init_common(dev, type, possible_crtcs,
>>>>> + pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION),
>>>>> + pipe_hw->cap->sblk->format_list,
>>>>> + pipe_hw->cap->sblk->num_formats,
>>>>> + pipe);
>>>>> + if (IS_ERR(plane))
>>>>> + return plane;
>>>>> +
>>>>> drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
>>>>> DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
>>>>> pipe, plane->base.id);
>>>>> +
>>>>> + return plane;
>>>>> +}
>>>>> +
>>>>> +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
>>>>> + enum drm_plane_type type,
>>>>> + unsigned long possible_crtcs)
>>>>> +{
>>>>> + struct drm_plane *plane = NULL;
>>>>> + struct msm_drm_private *priv = dev->dev_private;
>>>>> + struct dpu_kms *kms = to_dpu_kms(priv->kms);
>>>>> + bool has_inline_rotation = false;
>>>>> + const u32 *format_list = NULL;
>>>>> + u32 num_formats = 0;
>>>>> + int i;
>>>>> +
>>>>> + /* Determine the largest configuration that we can implement */
>>>>> + for (i = 0; i < kms->catalog->sspp_count; i++) {
>>>>> + const struct dpu_sspp_cfg *cfg = &kms->catalog->sspp[i];
>>>>> +
>>>>> + if (test_bit(DPU_SSPP_INLINE_ROTATION, &cfg->features))
>>>>> + has_inline_rotation = true;
>>>>> +
>>>>> + if (!format_list ||
>>>>> + cfg->sblk->csc_blk.len) {
>>>>
>>>> But format_list is being assigned to NULL just a few lines above. Why is
>>>> this check needed?
>>>
>>> It was assigned before the loop.
>>>
>>
>> Yes, I got this part but missed on why we needed the loop at all.
>
> Which set of formats should the virtual plane use?
>
>>>>
>>>> I dont get why this part can also goto dpu_plane_init_common() as it looks
>>>> identical to me.
>>>
>>> And it is not. For the non-virtual case there is no loop around formats
>>> list assignment.
>>>
>>
>> Ah okay, I misunderstood the logic. After reading the comment above the loop
>> I get what you are trying to do here.
>>
>> But I dont get why you really need to do that?
>>
>> 1) In this patch the relationship between virtual plane and SSPP is still
>> 1:1 so what is wrong to retain the sspp's actual format for the plane rather
>> than picking the best format (you are targetting Vig SSPP)
>
> No. With this patch there is no 1:1 relationship. The RM will select the
> SSPP that suits the requirements (YUV, scaling, rotation, etc).
>
Yes but there is always only one SSPP for one plane is what I meant.
That does not change till the next patch.
In that sense, I dont see why you need to expose the superset of formats.
>> In fact, that will reduce atomic_check() failures with this patch because
>> compositor will still work the same way as it used to work before by not
>> trying an unsupported format on a plane.
>
> The virtual plane should support any of the formats that the backing
> hardware can support. If (for example) we only had RGB-only and YUV-only
> hardware blocks, the driver would have to construct a _superset_ of
> those formats. Fortunately this is not the case and VIG supports a
> strict superset of what DMA (or RGB) SSPP supports.
>
Yes, thats why I said plane_formats_yuv is enough in my next point below
because Vig is super set of DMA or IOW Vig is the most feature rich plane.
>> If one plane maps to two SSPPs, then yes we can go with the superset of
>> formats but that comes in a later patch right?
>>
>> 2) So even if we want to do it this way from this patch itself, I think all
>> you are looking for is whether there is a Vig SSPP and if so use
>> plane_formats_yuv. There is no need for this loop IMO.
>>
>> 3) I noticed that virt_format_list is still present in the driver. If you
>> are planning to not use that perhaps drop it with this series.
>
> Ack
>
>>
>>>>
>>>>
>>>>> + format_list = cfg->sblk->format_list;
>>>>> + num_formats = cfg->sblk->num_formats;
>>>>> + }
>>>>> + }
>>>>> +
>>>>> + plane = dpu_plane_init_common(dev, type, possible_crtcs,
>>>>> + has_inline_rotation,
>>>>> + format_list,
>>>>> + num_formats,
>>>>> + SSPP_NONE);
>>>>
>>>> Ok, here is the part which we were discussing in
>>>>
>>>> https://patchwork.freedesktop.org/patch/582820/?series=131109&rev=1#comment_1087370
>>>>
>>>> So yes, that part belongs to this patch.
>>>
>>> I'll check it while preparing the next iteration.
>>>
>>>>
>>>>> + if (IS_ERR(plane))
>>>>> + return plane;
>>>>> +
>>>>> + drm_plane_helper_add(plane, &dpu_plane_virtual_helper_funcs);
>>>>> +
>>>>> + DPU_DEBUG("%s created virtual id:%u\n", plane->name, plane->base.id);
>>>>> +
>>>>> return plane;
>>>>> }
>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>>>>> index a3ae45dc95d0..15f7d60d8b85 100644
>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>>>>> @@ -30,6 +30,7 @@
>>>>> * @plane_fetch_bw: calculated BW per plane
>>>>> * @plane_clk: calculated clk per plane
>>>>> * @needs_dirtyfb: whether attached CRTC needs pixel data explicitly flushed
>>>>> + * @saved_fmt: format used by the plane's FB, saved for for virtual plane support
>>>>> */
>>>>> struct dpu_plane_state {
>>>>> struct drm_plane_state base;
>>>>> @@ -46,6 +47,8 @@ struct dpu_plane_state {
>>>>> u64 plane_clk;
>>>>> bool needs_dirtyfb;
>>>>> +
>>>>> + const struct dpu_format *saved_fmt;
>>>>> };
>>>>
>>>> Why is saved_fmt needed?
>>>>
>>>> The use-case which comes to my mind is lets say if we have a RGB format and
>>>> we need to switch to a YUV format, basically switch from DMA to ViG SSPP,
>>>> then yes we have to mark planes_changed as we need to switch the underlying
>>>> SSPP that time, but why cant we simply check that by means of a check to see
>>>> if the fmt is YUV and whether CSC block is present in the SSPP.
>>>
>>> Yes, correct. And vice versa, going from YUV to RGB might free the VIG
>>> SSPP.
>>>
>>>>
>>>> This will lead to dpu_crtc_reassign_planes() getting called for format
>>>> changes even when the new format might be available in the same SSPP.
>>>
>>> So use 'needs_vig' instead of storing the format? Sounds good to me.
>>>
>>
>> Yes thats the idea. Basically "needs_reassignment". You could even go from
>> Vig to DMA if the use-case can just use DMA to save up Vig.
>>
>> Also, do we really need to cache anything in the plane state to track this?
>>
>> If we have a function called dpu_crtc_needs_plane_reassignment() will go
>> through the current plane state and the current SSPP from the global state
>> and see if needs reassignment.
>
> No, looking at the global state won't be possible here. I'd have to lock
> the private object before consulting it, which might cause EDEADLOCK
> later on during resource reallocation. So all necessary information
> should be stored in the dpu_plane_state.
>
But you are already calling dpu_kms_get_global_state() in
dpu_crtc_reassign_planes().
>>
>>>>
>>>>> #define to_dpu_plane_state(x) \
>>>>> @@ -75,6 +78,16 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
>>>>> uint32_t pipe, enum drm_plane_type type,
>>>>> unsigned long possible_crtcs);
>>>>> +/**
>>>>> + * dpu_plane_init_virtual - create new dpu virtualized plane
>>>>> + * @dev: Pointer to DRM device
>>>>> + * @type: Plane type - PRIMARY/OVERLAY/CURSOR
>>>>> + * @possible_crtcs: bitmask of crtc that can be attached to the given pipe
>>>>> + */
>>>>> +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
>>>>> + enum drm_plane_type type,
>>>>> + unsigned long possible_crtcs);
>>>>> +
>>>>> /**
>>>>> * dpu_plane_color_fill - enables color fill on plane
>>>>> * @plane: Pointer to DRM plane object
>>>>> @@ -91,4 +104,10 @@ void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable);
>>>>> static inline void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) {}
>>>>> #endif
>>>>> +int dpu_assign_plane_resources(struct dpu_global_state *global_state,
>>>>> + struct drm_atomic_state *state,
>>>>> + struct drm_crtc *crtc,
>>>>> + struct drm_plane_state **states,
>>>>> + unsigned int num_planes);
>>>>> +
>>>>> #endif /* _DPU_PLANE_H_ */
>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>>>> index 44938ba7a2b7..7264a4d44a14 100644
>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>>>> @@ -694,6 +694,83 @@ int dpu_rm_reserve(
>>>>> return ret;
>>>>> }
>>>>> +struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
>>>>> + struct dpu_global_state *global_state,
>>>>> + struct drm_crtc *crtc,
>>>>> + struct dpu_rm_sspp_requirements *reqs)
>>>>> +{
>>>>> + uint32_t crtc_id = crtc->base.id;
>>>>> + unsigned int weight, best_weght = UINT_MAX;
>>>>
>>>> best_weight?
>>>
>>> Yes
>>>
>>>>
>>>>> + struct dpu_hw_sspp *hw_sspp;
>>>>> + unsigned long mask = 0;
>>>>> + int i, best_idx = -1;
>>>>> +
>>>>> + /*
>>>>> + * Don't take cursor feature into consideration until there is proper support for SSPP_CURSORn.
>>>>> + */
>>>>> + mask |= BIT(DPU_SSPP_CURSOR);
>>>>> +
>>>>> + if (reqs->scale)
>>>>> + mask |= BIT(DPU_SSPP_SCALER_RGB) |
>>>>> + BIT(DPU_SSPP_SCALER_QSEED2) |
>>>>> + BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE);
>>>>> +
>>>>> + if (reqs->yuv)
>>>>> + mask |= BIT(DPU_SSPP_CSC) |
>>>>> + BIT(DPU_SSPP_CSC_10BIT);
>>>>> +
>>>>> + if (reqs->rot90)
>>>>> + mask |= BIT(DPU_SSPP_INLINE_ROTATION);
>>>>> +
>>>>> + for (i = 0; i < ARRAY_SIZE(rm->hw_sspp); i++) {
>>>>> + if (!rm->hw_sspp[i])
>>>>> + continue;
>>>>> +
>>>>> + if (global_state->sspp_to_crtc_id[i])
>>>>> + continue;
>>>>> +
>>>>> + hw_sspp = rm->hw_sspp[i];
>>>>> +
>>>>> + /* skip incompatible planes */
>>>>> + if (reqs->scale && !hw_sspp->cap->sblk->scaler_blk.len)
>>>>> + continue;
>>>>> +
>>>>> + if (reqs->yuv && !hw_sspp->cap->sblk->csc_blk.len)
>>>>> + continue;
>>>>> +
>>>>> + if (reqs->rot90 && !(hw_sspp->cap->features & DPU_SSPP_INLINE_ROTATION))
>>>>> + continue;
>>>>> +
>>>>> + /*
>>>>> + * For non-yuv, non-scaled planes prefer simple (DMA or RGB)
>>>>> + * plane, falling back to VIG only if there are no such planes.
>>>>> + *
>>>>> + * This way we'd leave VIG sspps to be later used for YUV formats.
>>>>> + */
>>>>> + weight = hweight64(hw_sspp->cap->features & ~mask);
>>>>
>>>> This approach is assuming that ViG feature masks are more than DMA.
>>>> Hence the hweight of DMA SSPP's features is less than hweight of ViG SSPPs.
>>>>
>>>> Is this really true? Because there are other bits such as DMA_SDM845_MASK
>>>> which might increase the hweight of DMA SSPPs
>>>
>>> Which bits are present in the DMA mask, which are not present in the VIG
>>> mask? Also for the older platforms there are three kinds of planes: VIG,
>>> DMA and RGB. The selection algorithm should not require significant
>>> changes to support that case.
>>>
>>
>> DMA_SDM845_MASK has DPU_SSPP_QOS_8LVL which is not there in VIG_MSM8998_MASK
>> afaict. But we really cannot be counting the number of feature bits and
>> going by that.
>
> MSM8998 uses DMA_MSM8998_MASK, not DMA_SDM845_MASK.
>
>> Hence, inherently, going by hweight is not right because whenever we add a
>> catalog change to add a new feature bit to SSPP, we have to come back here
>> and make sure this logic will not break.
>>>>
>>>> I would rather make it simpler.
>>>>
>>>> 1) if we need scaling || yuv, then we have to get only a Vig
>>>> 2) else, first try to get a DMA SSPP
>>>
>>> How would you distinguish between VIG and DMA?
>>>
>>
>> the type SSPP_TYPE_VIG OR SSPP_TYPE_DMA. We also have a SSPP_TYPE_RGB so
>> that should address your concern about the third type of plane (Vig, DMA,
>> RGB).
>
> I don't particularly like the idea of using type. We still need to
> evaluate plane's features. Consider QCM2290, where VIG planes do not
> support scaling.
>
> I will evaluate if I can rework this part to use type, while still
> checking for the feature bit. BTW: should we prefer RGB or DMA plane if
> all other conditions are met?
>
Ok, qcm2290 really seems like an odd case but point taken.
I am fine if it needs to be a combination of type and feature bit but
certainly not hweight of feature bit. If you want to use type along with
presence of scaler blk feature bit thats fine.
I need to check if there is any feature loss in RGB Vs DMA. Let me check
and get back. This needs some history digging.
>>
>>
>>>> 3) if (2) fails, we have to try to get a ViG SSPP.
>>>>
>>>> Lets be more explicit about the SSPP type here rather than using hweight.
>>>>
>>>>
>>>>> + if (weight < best_weght) {
>>>>> + best_weght = weight;
>>>>> + best_idx = i;
>>>>> + }
>>>>> + }
>>>>> +
>>>>> + if (best_idx < 0)
>>>>> + return NULL;
>>>>> +
>>>>> + global_state->sspp_to_crtc_id[best_idx] = crtc_id;
>>>>> +
>>>>> + return rm->hw_sspp[best_idx];
>>>>> +}
>>>>> +
>>>>> +void dpu_rm_release_all_sspp(struct dpu_global_state *global_state,
>>>>> + struct drm_crtc *crtc)
>>>>> +{
>>>>> + uint32_t crtc_id = crtc->base.id;
>>>>> +
>>>>> + _dpu_rm_clear_mapping(global_state->sspp_to_crtc_id,
>>>>> + ARRAY_SIZE(global_state->sspp_to_crtc_id), crtc_id);
>>>>> +}
>>>>> +
>>>>> int dpu_rm_get_assigned_resources(struct dpu_rm *rm,
>>>>> struct dpu_global_state *global_state, uint32_t enc_id,
>>>>> enum dpu_hw_blk_type type, struct dpu_hw_blk **blks, int blks_size)
>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
>>>>> index e63db8ace6b9..bf9110547385 100644
>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
>>>>> @@ -37,6 +37,12 @@ struct dpu_rm {
>>>>> struct dpu_hw_blk *cdm_blk;
>>>>> };
>>>>> +struct dpu_rm_sspp_requirements {
>>>>> + bool yuv;
>>>>> + bool scale;
>>>>> + bool rot90;
>>>>> +};
>>>>> +
>>>>> /**
>>>>> * dpu_rm_init - Read hardware catalog and create reservation tracking objects
>>>>> * for all HW blocks.
>>>>> @@ -82,6 +88,28 @@ int dpu_rm_reserve(struct dpu_rm *rm,
>>>>> void dpu_rm_release(struct dpu_global_state *global_state,
>>>>> struct drm_encoder *enc);
>>>>> +/**
>>>>> + * dpu_rm_reserve_sspp - Reserve the required SSPP for the provided CRTC
>>>>> + * @rm: DPU Resource Manager handle
>>>>> + * @global_state: private global state
>>>>> + * @crtc: DRM CRTC handle
>>>>> + * @reqs: SSPP required features
>>>>> + */
>>>>> +struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
>>>>> + struct dpu_global_state *global_state,
>>>>> + struct drm_crtc *crtc,
>>>>> + struct dpu_rm_sspp_requirements *reqs);
>>>>> +
>>>>> +/**
>>>>> + * dpu_rm_release_all_sspp - Given the CRTC, release all SSPP
>>>>> + * blocks previously reserved for that use case.
>>>>> + * @rm: DPU Resource Manager handle
>>>>> + * @crtc: DRM CRTC handle
>>>>> + * @Return: 0 on Success otherwise -ERROR
>>>>> + */
>>>>
>>>> This is void so does not return anything?
>
> Yes
>
>>>>
>>>>> +void dpu_rm_release_all_sspp(struct dpu_global_state *global_state,
>>>>> + struct drm_crtc *crtc);
>>>>> +
>>>>> /**
>>>>> * Get hw resources of the given type that are assigned to this encoder.
>>>>> */
>>>
>
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 08/13] drm/msm/dpu: add support for virtual planes
2024-06-07 21:39 ` Abhinav Kumar
@ 2024-06-07 22:26 ` Dmitry Baryshkov
2024-06-07 23:55 ` Abhinav Kumar
0 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-06-07 22:26 UTC (permalink / raw)
To: Abhinav Kumar
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On Sat, 8 Jun 2024 at 00:39, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>
>
>
> On 6/7/2024 2:10 PM, Dmitry Baryshkov wrote:
> > On Fri, Jun 07, 2024 at 12:22:16PM -0700, Abhinav Kumar wrote:
> >>
> >>
> >> On 6/7/2024 12:16 AM, Dmitry Baryshkov wrote:
> >>> On Thu, Jun 06, 2024 at 03:21:11PM -0700, Abhinav Kumar wrote:
> >>>> On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> >>>>> Only several SSPP blocks support such features as YUV output or scaling,
> >>>>> thus different DRM planes have different features. Properly utilizing
> >>>>> all planes requires the attention of the compositor, who should
> >>>>> prefer simpler planes to YUV-supporting ones. Otherwise it is very easy
> >>>>> to end up in a situation when all featureful planes are already
> >>>>> allocated for simple windows, leaving no spare plane for YUV playback.
> >>>>>
> >>>>> To solve this problem make all planes virtual. Each plane is registered
> >>>>> as if it supports all possible features, but then at the runtime during
> >>>>> the atomic_check phase the driver selects backing SSPP block for each
> >>>>> plane.
> >>>>>
> >>>>> Note, this does not provide support for using two different SSPP blocks
> >>>>> for a single plane or using two rectangles of an SSPP to drive two
> >>>>> planes. Each plane still gets its own SSPP and can utilize either a solo
> >>>>> rectangle or both multirect rectangles depending on the resolution.
> >>>>>
> >>>>> Note #2: By default support for virtual planes is turned off and the
> >>>>> driver still uses old code path with preallocated SSPP block for each
> >>>>> plane. To enable virtual planes, pass 'msm.dpu_use_virtual_planes=1'
> >>>>> kernel parameter.
> >>>>>
> >>>>
> >>>> I like the overall approach in this patch. Some comments below.
> >>>>
> >>>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> >>>>> ---
> >>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 50 +++++
> >>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 10 +-
> >>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 4 +
> >>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 230 +++++++++++++++++++---
> >>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 19 ++
> >>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 77 ++++++++
> >>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 28 +++
> >>>>> 7 files changed, 390 insertions(+), 28 deletions(-)
> >>>>>
> >>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> >>>>> index 88c2e51ab166..794c5643584f 100644
> >>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> >>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> >>>>> @@ -1168,6 +1168,49 @@ static bool dpu_crtc_needs_dirtyfb(struct drm_crtc_state *cstate)
> >>>>> return false;
> >>>>> }
> >>>>> +static int dpu_crtc_reassign_planes(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
> >>>>> +{
> >>>>> + int total_planes = crtc->dev->mode_config.num_total_plane;
> >>>>> + struct drm_atomic_state *state = crtc_state->state;
> >>>>> + struct dpu_global_state *global_state;
> >>>>> + struct drm_plane_state **states;
> >>>>> + struct drm_plane *plane;
> >>>>> + int ret;
> >>>>> +
> >>>>> + global_state = dpu_kms_get_global_state(crtc_state->state);
> >>>>> + if (IS_ERR(global_state))
> >>>>> + return PTR_ERR(global_state);
> >>>>> +
> >>>>> + dpu_rm_release_all_sspp(global_state, crtc);
> >>>>> +
> >>>>
> >>>> Do we need to call dpu_rm_release_all_sspp() even in the
> >>>> _dpu_plane_atomic_disable()?
> >>>
> >>> It allows the driver to optimize the usage of the SSPP rectangles.
> >>>
> >>
> >> No, what I meant was that we should call dpu_rm_release_all_sspp() in
> >> dpu_plane_atomic_update() as well because in the atomic_check() path where
> >> its called today, its being called only for zpos_changed and planes_changed
> >> but during disable we must call this for sure.
> >
> > No. the dpu_rm_release_all_sspp() should only be called during check.
> > When dpu_plane_atomic_update() is called, the state should already be
> > finalised. The atomic_check() callback is called when a plane is going
> > to be disabled.
> >
>
> atomic_check() will be called when plane is disabled but
> dpu_rm_release_all_sspp() may not be called as it is protected by
> zpos_changed and planes_changed. OR you need to add a !visible check
> here to call dpu_rm_release_all_sspp() that time. Thats whay I wrote
> previously.
Unless I miss something, if a plane gets disabled, then obviously
planes_changed is true.
[trimmed]
>
> >>>>> @@ -1486,7 +1593,7 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
> >>>>> supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
> >>>>> - if (pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION))
> >>>>> + if (inline_rotation)
> >>>>> supported_rotations |= DRM_MODE_ROTATE_MASK;
> >>>>> drm_plane_create_rotation_property(plane,
> >>>>> @@ -1494,10 +1601,81 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
> >>>>> drm_plane_enable_fb_damage_clips(plane);
> >>>>> - /* success! finalize initialization */
> >>>>> + DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
> >>>>> + pipe, plane->base.id);
> >>>>> + return plane;
> >>>>> +}
> >>>>> +
> >>>>> +struct drm_plane *dpu_plane_init(struct drm_device *dev,
> >>>>> + uint32_t pipe, enum drm_plane_type type,
> >>>>> + unsigned long possible_crtcs)
> >>>>> +{
> >>>>> + struct drm_plane *plane = NULL;
> >>>>> + struct msm_drm_private *priv = dev->dev_private;
> >>>>> + struct dpu_kms *kms = to_dpu_kms(priv->kms);
> >>>>> + struct dpu_hw_sspp *pipe_hw;
> >>>>> +
> >>>>> + /* initialize underlying h/w driver */
> >>>>> + pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);
> >>>>> + if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {
> >>>>> + DPU_ERROR("[%u]SSPP is invalid\n", pipe);
> >>>>> + return ERR_PTR(-EINVAL);
> >>>>> + }
> >>>>> +
> >>>>> +
> >>>>> + plane = dpu_plane_init_common(dev, type, possible_crtcs,
> >>>>> + pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION),
> >>>>> + pipe_hw->cap->sblk->format_list,
> >>>>> + pipe_hw->cap->sblk->num_formats,
> >>>>> + pipe);
> >>>>> + if (IS_ERR(plane))
> >>>>> + return plane;
> >>>>> +
> >>>>> drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
> >>>>> DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
> >>>>> pipe, plane->base.id);
> >>>>> +
> >>>>> + return plane;
> >>>>> +}
> >>>>> +
> >>>>> +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
> >>>>> + enum drm_plane_type type,
> >>>>> + unsigned long possible_crtcs)
> >>>>> +{
> >>>>> + struct drm_plane *plane = NULL;
> >>>>> + struct msm_drm_private *priv = dev->dev_private;
> >>>>> + struct dpu_kms *kms = to_dpu_kms(priv->kms);
> >>>>> + bool has_inline_rotation = false;
> >>>>> + const u32 *format_list = NULL;
> >>>>> + u32 num_formats = 0;
> >>>>> + int i;
> >>>>> +
> >>>>> + /* Determine the largest configuration that we can implement */
> >>>>> + for (i = 0; i < kms->catalog->sspp_count; i++) {
> >>>>> + const struct dpu_sspp_cfg *cfg = &kms->catalog->sspp[i];
> >>>>> +
> >>>>> + if (test_bit(DPU_SSPP_INLINE_ROTATION, &cfg->features))
> >>>>> + has_inline_rotation = true;
> >>>>> +
> >>>>> + if (!format_list ||
> >>>>> + cfg->sblk->csc_blk.len) {
> >>>>
> >>>> But format_list is being assigned to NULL just a few lines above. Why is
> >>>> this check needed?
> >>>
> >>> It was assigned before the loop.
> >>>
> >>
> >> Yes, I got this part but missed on why we needed the loop at all.
> >
> > Which set of formats should the virtual plane use?
> >
> >>>>
> >>>> I dont get why this part can also goto dpu_plane_init_common() as it looks
> >>>> identical to me.
> >>>
> >>> And it is not. For the non-virtual case there is no loop around formats
> >>> list assignment.
> >>>
> >>
> >> Ah okay, I misunderstood the logic. After reading the comment above the loop
> >> I get what you are trying to do here.
> >>
> >> But I dont get why you really need to do that?
> >>
> >> 1) In this patch the relationship between virtual plane and SSPP is still
> >> 1:1 so what is wrong to retain the sspp's actual format for the plane rather
> >> than picking the best format (you are targetting Vig SSPP)
> >
> > No. With this patch there is no 1:1 relationship. The RM will select the
> > SSPP that suits the requirements (YUV, scaling, rotation, etc).
> >
>
> Yes but there is always only one SSPP for one plane is what I meant.
> That does not change till the next patch.
>
> In that sense, I dont see why you need to expose the superset of formats.
Let me please repeat my question: what set of formats should be used
for plane init?
>
> >> In fact, that will reduce atomic_check() failures with this patch because
> >> compositor will still work the same way as it used to work before by not
> >> trying an unsupported format on a plane.
> >
> > The virtual plane should support any of the formats that the backing
> > hardware can support. If (for example) we only had RGB-only and YUV-only
> > hardware blocks, the driver would have to construct a _superset_ of
> > those formats. Fortunately this is not the case and VIG supports a
> > strict superset of what DMA (or RGB) SSPP supports.
> >
>
> Yes, thats why I said plane_formats_yuv is enough in my next point below
> because Vig is super set of DMA or IOW Vig is the most feature rich plane.
QCM2290 doesn't have YUV support if I'm not mistaken.
>
> >> If one plane maps to two SSPPs, then yes we can go with the superset of
> >> formats but that comes in a later patch right?
> >>
> >> 2) So even if we want to do it this way from this patch itself, I think all
> >> you are looking for is whether there is a Vig SSPP and if so use
> >> plane_formats_yuv. There is no need for this loop IMO.
> >>
> >> 3) I noticed that virt_format_list is still present in the driver. If you
> >> are planning to not use that perhaps drop it with this series.
> >
> > Ack
> >
> >>
> >>>>
> >>>>
> >>>>> + format_list = cfg->sblk->format_list;
> >>>>> + num_formats = cfg->sblk->num_formats;
> >>>>> + }
> >>>>> + }
> >>>>> +
> >>>>> + plane = dpu_plane_init_common(dev, type, possible_crtcs,
> >>>>> + has_inline_rotation,
> >>>>> + format_list,
> >>>>> + num_formats,
> >>>>> + SSPP_NONE);
> >>>>
> >>>> Ok, here is the part which we were discussing in
> >>>>
> >>>> https://patchwork.freedesktop.org/patch/582820/?series=131109&rev=1#comment_1087370
> >>>>
> >>>> So yes, that part belongs to this patch.
> >>>
> >>> I'll check it while preparing the next iteration.
> >>>
> >>>>
> >>>>> + if (IS_ERR(plane))
> >>>>> + return plane;
> >>>>> +
> >>>>> + drm_plane_helper_add(plane, &dpu_plane_virtual_helper_funcs);
> >>>>> +
> >>>>> + DPU_DEBUG("%s created virtual id:%u\n", plane->name, plane->base.id);
> >>>>> +
> >>>>> return plane;
> >>>>> }
> >>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> >>>>> index a3ae45dc95d0..15f7d60d8b85 100644
> >>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> >>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> >>>>> @@ -30,6 +30,7 @@
> >>>>> * @plane_fetch_bw: calculated BW per plane
> >>>>> * @plane_clk: calculated clk per plane
> >>>>> * @needs_dirtyfb: whether attached CRTC needs pixel data explicitly flushed
> >>>>> + * @saved_fmt: format used by the plane's FB, saved for for virtual plane support
> >>>>> */
> >>>>> struct dpu_plane_state {
> >>>>> struct drm_plane_state base;
> >>>>> @@ -46,6 +47,8 @@ struct dpu_plane_state {
> >>>>> u64 plane_clk;
> >>>>> bool needs_dirtyfb;
> >>>>> +
> >>>>> + const struct dpu_format *saved_fmt;
> >>>>> };
> >>>>
> >>>> Why is saved_fmt needed?
> >>>>
> >>>> The use-case which comes to my mind is lets say if we have a RGB format and
> >>>> we need to switch to a YUV format, basically switch from DMA to ViG SSPP,
> >>>> then yes we have to mark planes_changed as we need to switch the underlying
> >>>> SSPP that time, but why cant we simply check that by means of a check to see
> >>>> if the fmt is YUV and whether CSC block is present in the SSPP.
> >>>
> >>> Yes, correct. And vice versa, going from YUV to RGB might free the VIG
> >>> SSPP.
> >>>
> >>>>
> >>>> This will lead to dpu_crtc_reassign_planes() getting called for format
> >>>> changes even when the new format might be available in the same SSPP.
> >>>
> >>> So use 'needs_vig' instead of storing the format? Sounds good to me.
> >>>
> >>
> >> Yes thats the idea. Basically "needs_reassignment". You could even go from
> >> Vig to DMA if the use-case can just use DMA to save up Vig.
> >>
> >> Also, do we really need to cache anything in the plane state to track this?
> >>
> >> If we have a function called dpu_crtc_needs_plane_reassignment() will go
> >> through the current plane state and the current SSPP from the global state
> >> and see if needs reassignment.
> >
> > No, looking at the global state won't be possible here. I'd have to lock
> > the private object before consulting it, which might cause EDEADLOCK
> > later on during resource reallocation. So all necessary information
> > should be stored in the dpu_plane_state.
> >
>
> But you are already calling dpu_kms_get_global_state() in
> dpu_crtc_reassign_planes().
It happens at a different point. And I'm not sure how modeset locking
will react to an attempt to lock the private object twice.
>
> >>
> >>>>
> >>>>> #define to_dpu_plane_state(x) \
> >>>>> @@ -75,6 +78,16 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
> >>>>> uint32_t pipe, enum drm_plane_type type,
> >>>>> unsigned long possible_crtcs);
> >>>>> +/**
> >>>>> + * dpu_plane_init_virtual - create new dpu virtualized plane
> >>>>> + * @dev: Pointer to DRM device
> >>>>> + * @type: Plane type - PRIMARY/OVERLAY/CURSOR
> >>>>> + * @possible_crtcs: bitmask of crtc that can be attached to the given pipe
> >>>>> + */
> >>>>> +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
> >>>>> + enum drm_plane_type type,
> >>>>> + unsigned long possible_crtcs);
> >>>>> +
> >>>>> /**
> >>>>> * dpu_plane_color_fill - enables color fill on plane
> >>>>> * @plane: Pointer to DRM plane object
> >>>>> @@ -91,4 +104,10 @@ void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable);
> >>>>> static inline void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) {}
> >>>>> #endif
> >>>>> +int dpu_assign_plane_resources(struct dpu_global_state *global_state,
> >>>>> + struct drm_atomic_state *state,
> >>>>> + struct drm_crtc *crtc,
> >>>>> + struct drm_plane_state **states,
> >>>>> + unsigned int num_planes);
> >>>>> +
> >>>>> #endif /* _DPU_PLANE_H_ */
> >>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> >>>>> index 44938ba7a2b7..7264a4d44a14 100644
> >>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> >>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> >>>>> @@ -694,6 +694,83 @@ int dpu_rm_reserve(
> >>>>> return ret;
> >>>>> }
> >>>>> +struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
> >>>>> + struct dpu_global_state *global_state,
> >>>>> + struct drm_crtc *crtc,
> >>>>> + struct dpu_rm_sspp_requirements *reqs)
> >>>>> +{
> >>>>> + uint32_t crtc_id = crtc->base.id;
> >>>>> + unsigned int weight, best_weght = UINT_MAX;
> >>>>
> >>>> best_weight?
> >>>
> >>> Yes
> >>>
> >>>>
> >>>>> + struct dpu_hw_sspp *hw_sspp;
> >>>>> + unsigned long mask = 0;
> >>>>> + int i, best_idx = -1;
> >>>>> +
> >>>>> + /*
> >>>>> + * Don't take cursor feature into consideration until there is proper support for SSPP_CURSORn.
> >>>>> + */
> >>>>> + mask |= BIT(DPU_SSPP_CURSOR);
> >>>>> +
> >>>>> + if (reqs->scale)
> >>>>> + mask |= BIT(DPU_SSPP_SCALER_RGB) |
> >>>>> + BIT(DPU_SSPP_SCALER_QSEED2) |
> >>>>> + BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE);
> >>>>> +
> >>>>> + if (reqs->yuv)
> >>>>> + mask |= BIT(DPU_SSPP_CSC) |
> >>>>> + BIT(DPU_SSPP_CSC_10BIT);
> >>>>> +
> >>>>> + if (reqs->rot90)
> >>>>> + mask |= BIT(DPU_SSPP_INLINE_ROTATION);
> >>>>> +
> >>>>> + for (i = 0; i < ARRAY_SIZE(rm->hw_sspp); i++) {
> >>>>> + if (!rm->hw_sspp[i])
> >>>>> + continue;
> >>>>> +
> >>>>> + if (global_state->sspp_to_crtc_id[i])
> >>>>> + continue;
> >>>>> +
> >>>>> + hw_sspp = rm->hw_sspp[i];
> >>>>> +
> >>>>> + /* skip incompatible planes */
> >>>>> + if (reqs->scale && !hw_sspp->cap->sblk->scaler_blk.len)
> >>>>> + continue;
> >>>>> +
> >>>>> + if (reqs->yuv && !hw_sspp->cap->sblk->csc_blk.len)
> >>>>> + continue;
> >>>>> +
> >>>>> + if (reqs->rot90 && !(hw_sspp->cap->features & DPU_SSPP_INLINE_ROTATION))
> >>>>> + continue;
> >>>>> +
> >>>>> + /*
> >>>>> + * For non-yuv, non-scaled planes prefer simple (DMA or RGB)
> >>>>> + * plane, falling back to VIG only if there are no such planes.
> >>>>> + *
> >>>>> + * This way we'd leave VIG sspps to be later used for YUV formats.
> >>>>> + */
> >>>>> + weight = hweight64(hw_sspp->cap->features & ~mask);
> >>>>
> >>>> This approach is assuming that ViG feature masks are more than DMA.
> >>>> Hence the hweight of DMA SSPP's features is less than hweight of ViG SSPPs.
> >>>>
> >>>> Is this really true? Because there are other bits such as DMA_SDM845_MASK
> >>>> which might increase the hweight of DMA SSPPs
> >>>
> >>> Which bits are present in the DMA mask, which are not present in the VIG
> >>> mask? Also for the older platforms there are three kinds of planes: VIG,
> >>> DMA and RGB. The selection algorithm should not require significant
> >>> changes to support that case.
> >>>
> >>
> >> DMA_SDM845_MASK has DPU_SSPP_QOS_8LVL which is not there in VIG_MSM8998_MASK
> >> afaict. But we really cannot be counting the number of feature bits and
> >> going by that.
> >
> > MSM8998 uses DMA_MSM8998_MASK, not DMA_SDM845_MASK.
> >
> >> Hence, inherently, going by hweight is not right because whenever we add a
> >> catalog change to add a new feature bit to SSPP, we have to come back here
> >> and make sure this logic will not break.
> >>>>
> >>>> I would rather make it simpler.
> >>>>
> >>>> 1) if we need scaling || yuv, then we have to get only a Vig
> >>>> 2) else, first try to get a DMA SSPP
> >>>
> >>> How would you distinguish between VIG and DMA?
> >>>
> >>
> >> the type SSPP_TYPE_VIG OR SSPP_TYPE_DMA. We also have a SSPP_TYPE_RGB so
> >> that should address your concern about the third type of plane (Vig, DMA,
> >> RGB).
> >
> > I don't particularly like the idea of using type. We still need to
> > evaluate plane's features. Consider QCM2290, where VIG planes do not
> > support scaling.
> >
> > I will evaluate if I can rework this part to use type, while still
> > checking for the feature bit. BTW: should we prefer RGB or DMA plane if
> > all other conditions are met?
> >
>
> Ok, qcm2290 really seems like an odd case but point taken.
>
> I am fine if it needs to be a combination of type and feature bit but
> certainly not hweight of feature bit. If you want to use type along with
> presence of scaler blk feature bit thats fine.
>
> I need to check if there is any feature loss in RGB Vs DMA. Let me check
> and get back. This needs some history digging.
Sure.
>
> >>
> >>
> >>>> 3) if (2) fails, we have to try to get a ViG SSPP.
> >>>>
> >>>> Lets be more explicit about the SSPP type here rather than using hweight.
> >>>>
> >>>>
> >>>>> + if (weight < best_weght) {
> >>>>> + best_weght = weight;
> >>>>> + best_idx = i;
> >>>>> + }
> >>>>> + }
> >>>>> +
> >>>>> + if (best_idx < 0)
> >>>>> + return NULL;
> >>>>> +
> >>>>> + global_state->sspp_to_crtc_id[best_idx] = crtc_id;
> >>>>> +
> >>>>> + return rm->hw_sspp[best_idx];
> >>>>> +}
> >>>>> +
> >>>>> +void dpu_rm_release_all_sspp(struct dpu_global_state *global_state,
> >>>>> + struct drm_crtc *crtc)
> >>>>> +{
> >>>>> + uint32_t crtc_id = crtc->base.id;
> >>>>> +
> >>>>> + _dpu_rm_clear_mapping(global_state->sspp_to_crtc_id,
> >>>>> + ARRAY_SIZE(global_state->sspp_to_crtc_id), crtc_id);
> >>>>> +}
> >>>>> +
> >>>>> int dpu_rm_get_assigned_resources(struct dpu_rm *rm,
> >>>>> struct dpu_global_state *global_state, uint32_t enc_id,
> >>>>> enum dpu_hw_blk_type type, struct dpu_hw_blk **blks, int blks_size)
> >>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> >>>>> index e63db8ace6b9..bf9110547385 100644
> >>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> >>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> >>>>> @@ -37,6 +37,12 @@ struct dpu_rm {
> >>>>> struct dpu_hw_blk *cdm_blk;
> >>>>> };
> >>>>> +struct dpu_rm_sspp_requirements {
> >>>>> + bool yuv;
> >>>>> + bool scale;
> >>>>> + bool rot90;
> >>>>> +};
> >>>>> +
> >>>>> /**
> >>>>> * dpu_rm_init - Read hardware catalog and create reservation tracking objects
> >>>>> * for all HW blocks.
> >>>>> @@ -82,6 +88,28 @@ int dpu_rm_reserve(struct dpu_rm *rm,
> >>>>> void dpu_rm_release(struct dpu_global_state *global_state,
> >>>>> struct drm_encoder *enc);
> >>>>> +/**
> >>>>> + * dpu_rm_reserve_sspp - Reserve the required SSPP for the provided CRTC
> >>>>> + * @rm: DPU Resource Manager handle
> >>>>> + * @global_state: private global state
> >>>>> + * @crtc: DRM CRTC handle
> >>>>> + * @reqs: SSPP required features
> >>>>> + */
> >>>>> +struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
> >>>>> + struct dpu_global_state *global_state,
> >>>>> + struct drm_crtc *crtc,
> >>>>> + struct dpu_rm_sspp_requirements *reqs);
> >>>>> +
> >>>>> +/**
> >>>>> + * dpu_rm_release_all_sspp - Given the CRTC, release all SSPP
> >>>>> + * blocks previously reserved for that use case.
> >>>>> + * @rm: DPU Resource Manager handle
> >>>>> + * @crtc: DRM CRTC handle
> >>>>> + * @Return: 0 on Success otherwise -ERROR
> >>>>> + */
> >>>>
> >>>> This is void so does not return anything?
> >
> > Yes
> >
> >>>>
> >>>>> +void dpu_rm_release_all_sspp(struct dpu_global_state *global_state,
> >>>>> + struct drm_crtc *crtc);
> >>>>> +
> >>>>> /**
> >>>>> * Get hw resources of the given type that are assigned to this encoder.
> >>>>> */
> >>>
> >
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 08/13] drm/msm/dpu: add support for virtual planes
2024-06-07 22:26 ` Dmitry Baryshkov
@ 2024-06-07 23:55 ` Abhinav Kumar
2024-06-08 0:57 ` Dmitry Baryshkov
0 siblings, 1 reply; 50+ messages in thread
From: Abhinav Kumar @ 2024-06-07 23:55 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On 6/7/2024 3:26 PM, Dmitry Baryshkov wrote:
> On Sat, 8 Jun 2024 at 00:39, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>>
>>
>>
>> On 6/7/2024 2:10 PM, Dmitry Baryshkov wrote:
>>> On Fri, Jun 07, 2024 at 12:22:16PM -0700, Abhinav Kumar wrote:
>>>>
>>>>
>>>> On 6/7/2024 12:16 AM, Dmitry Baryshkov wrote:
>>>>> On Thu, Jun 06, 2024 at 03:21:11PM -0700, Abhinav Kumar wrote:
>>>>>> On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
>>>>>>> Only several SSPP blocks support such features as YUV output or scaling,
>>>>>>> thus different DRM planes have different features. Properly utilizing
>>>>>>> all planes requires the attention of the compositor, who should
>>>>>>> prefer simpler planes to YUV-supporting ones. Otherwise it is very easy
>>>>>>> to end up in a situation when all featureful planes are already
>>>>>>> allocated for simple windows, leaving no spare plane for YUV playback.
>>>>>>>
>>>>>>> To solve this problem make all planes virtual. Each plane is registered
>>>>>>> as if it supports all possible features, but then at the runtime during
>>>>>>> the atomic_check phase the driver selects backing SSPP block for each
>>>>>>> plane.
>>>>>>>
>>>>>>> Note, this does not provide support for using two different SSPP blocks
>>>>>>> for a single plane or using two rectangles of an SSPP to drive two
>>>>>>> planes. Each plane still gets its own SSPP and can utilize either a solo
>>>>>>> rectangle or both multirect rectangles depending on the resolution.
>>>>>>>
>>>>>>> Note #2: By default support for virtual planes is turned off and the
>>>>>>> driver still uses old code path with preallocated SSPP block for each
>>>>>>> plane. To enable virtual planes, pass 'msm.dpu_use_virtual_planes=1'
>>>>>>> kernel parameter.
>>>>>>>
>>>>>>
>>>>>> I like the overall approach in this patch. Some comments below.
>>>>>>
>>>>>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>>>>>> ---
>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 50 +++++
>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 10 +-
>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 4 +
>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 230 +++++++++++++++++++---
>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 19 ++
>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 77 ++++++++
>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 28 +++
>>>>>>> 7 files changed, 390 insertions(+), 28 deletions(-)
>>>>>>>
>>>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>>>> index 88c2e51ab166..794c5643584f 100644
>>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>>>> @@ -1168,6 +1168,49 @@ static bool dpu_crtc_needs_dirtyfb(struct drm_crtc_state *cstate)
>>>>>>> return false;
>>>>>>> }
>>>>>>> +static int dpu_crtc_reassign_planes(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
>>>>>>> +{
>>>>>>> + int total_planes = crtc->dev->mode_config.num_total_plane;
>>>>>>> + struct drm_atomic_state *state = crtc_state->state;
>>>>>>> + struct dpu_global_state *global_state;
>>>>>>> + struct drm_plane_state **states;
>>>>>>> + struct drm_plane *plane;
>>>>>>> + int ret;
>>>>>>> +
>>>>>>> + global_state = dpu_kms_get_global_state(crtc_state->state);
>>>>>>> + if (IS_ERR(global_state))
>>>>>>> + return PTR_ERR(global_state);
>>>>>>> +
>>>>>>> + dpu_rm_release_all_sspp(global_state, crtc);
>>>>>>> +
>>>>>>
>>>>>> Do we need to call dpu_rm_release_all_sspp() even in the
>>>>>> _dpu_plane_atomic_disable()?
>>>>>
>>>>> It allows the driver to optimize the usage of the SSPP rectangles.
>>>>>
>>>>
>>>> No, what I meant was that we should call dpu_rm_release_all_sspp() in
>>>> dpu_plane_atomic_update() as well because in the atomic_check() path where
>>>> its called today, its being called only for zpos_changed and planes_changed
>>>> but during disable we must call this for sure.
>>>
>>> No. the dpu_rm_release_all_sspp() should only be called during check.
>>> When dpu_plane_atomic_update() is called, the state should already be
>>> finalised. The atomic_check() callback is called when a plane is going
>>> to be disabled.
>>>
>>
>> atomic_check() will be called when plane is disabled but
>> dpu_rm_release_all_sspp() may not be called as it is protected by
>> zpos_changed and planes_changed. OR you need to add a !visible check
>> here to call dpu_rm_release_all_sspp() that time. Thats whay I wrote
>> previously.
>
> Unless I miss something, if a plane gets disabled, then obviously
> planes_changed is true.
>
> [trimmed]
>
Do you mean DRM fwk sets planes_changed correctly for this case?
Currently we have
if (!new_state->visible) {
_dpu_plane_atomic_disable(plane);
} else {
dpu_plane_sspp_atomic_update(plane);
}
So I wanted to ensure that when plane gets disabled, its SSPP is freed
too. If this is confirmed, I do not have any concerns.
>>
>>>>>>> @@ -1486,7 +1593,7 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
>>>>>>> supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
>>>>>>> - if (pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION))
>>>>>>> + if (inline_rotation)
>>>>>>> supported_rotations |= DRM_MODE_ROTATE_MASK;
>>>>>>> drm_plane_create_rotation_property(plane,
>>>>>>> @@ -1494,10 +1601,81 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
>>>>>>> drm_plane_enable_fb_damage_clips(plane);
>>>>>>> - /* success! finalize initialization */
>>>>>>> + DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
>>>>>>> + pipe, plane->base.id);
>>>>>>> + return plane;
>>>>>>> +}
>>>>>>> +
>>>>>>> +struct drm_plane *dpu_plane_init(struct drm_device *dev,
>>>>>>> + uint32_t pipe, enum drm_plane_type type,
>>>>>>> + unsigned long possible_crtcs)
>>>>>>> +{
>>>>>>> + struct drm_plane *plane = NULL;
>>>>>>> + struct msm_drm_private *priv = dev->dev_private;
>>>>>>> + struct dpu_kms *kms = to_dpu_kms(priv->kms);
>>>>>>> + struct dpu_hw_sspp *pipe_hw;
>>>>>>> +
>>>>>>> + /* initialize underlying h/w driver */
>>>>>>> + pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);
>>>>>>> + if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {
>>>>>>> + DPU_ERROR("[%u]SSPP is invalid\n", pipe);
>>>>>>> + return ERR_PTR(-EINVAL);
>>>>>>> + }
>>>>>>> +
>>>>>>> +
>>>>>>> + plane = dpu_plane_init_common(dev, type, possible_crtcs,
>>>>>>> + pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION),
>>>>>>> + pipe_hw->cap->sblk->format_list,
>>>>>>> + pipe_hw->cap->sblk->num_formats,
>>>>>>> + pipe);
>>>>>>> + if (IS_ERR(plane))
>>>>>>> + return plane;
>>>>>>> +
>>>>>>> drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
>>>>>>> DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
>>>>>>> pipe, plane->base.id);
>>>>>>> +
>>>>>>> + return plane;
>>>>>>> +}
>>>>>>> +
>>>>>>> +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
>>>>>>> + enum drm_plane_type type,
>>>>>>> + unsigned long possible_crtcs)
>>>>>>> +{
>>>>>>> + struct drm_plane *plane = NULL;
>>>>>>> + struct msm_drm_private *priv = dev->dev_private;
>>>>>>> + struct dpu_kms *kms = to_dpu_kms(priv->kms);
>>>>>>> + bool has_inline_rotation = false;
>>>>>>> + const u32 *format_list = NULL;
>>>>>>> + u32 num_formats = 0;
>>>>>>> + int i;
>>>>>>> +
>>>>>>> + /* Determine the largest configuration that we can implement */
>>>>>>> + for (i = 0; i < kms->catalog->sspp_count; i++) {
>>>>>>> + const struct dpu_sspp_cfg *cfg = &kms->catalog->sspp[i];
>>>>>>> +
>>>>>>> + if (test_bit(DPU_SSPP_INLINE_ROTATION, &cfg->features))
>>>>>>> + has_inline_rotation = true;
>>>>>>> +
>>>>>>> + if (!format_list ||
>>>>>>> + cfg->sblk->csc_blk.len) {
>>>>>>
>>>>>> But format_list is being assigned to NULL just a few lines above. Why is
>>>>>> this check needed?
>>>>>
>>>>> It was assigned before the loop.
>>>>>
>>>>
>>>> Yes, I got this part but missed on why we needed the loop at all.
>>>
>>> Which set of formats should the virtual plane use?
>>>
>>>>>>
>>>>>> I dont get why this part can also goto dpu_plane_init_common() as it looks
>>>>>> identical to me.
>>>>>
>>>>> And it is not. For the non-virtual case there is no loop around formats
>>>>> list assignment.
>>>>>
>>>>
>>>> Ah okay, I misunderstood the logic. After reading the comment above the loop
>>>> I get what you are trying to do here.
>>>>
>>>> But I dont get why you really need to do that?
>>>>
>>>> 1) In this patch the relationship between virtual plane and SSPP is still
>>>> 1:1 so what is wrong to retain the sspp's actual format for the plane rather
>>>> than picking the best format (you are targetting Vig SSPP)
>>>
>>> No. With this patch there is no 1:1 relationship. The RM will select the
>>> SSPP that suits the requirements (YUV, scaling, rotation, etc).
>>>
>>
>> Yes but there is always only one SSPP for one plane is what I meant.
>> That does not change till the next patch.
>>
>> In that sense, I dont see why you need to expose the superset of formats.
>
> Let me please repeat my question: what set of formats should be used
> for plane init?
>
So, my point here was that in the loop, in this patch, we create one
plane for one SSPP, why dont we just use the same SSPP's format for that
plane.
In the next patch, when the same plane can attach to two different
SSPPs, we will use the superset of the SSPPs. IOW, do we need the
superset in this patch itself?
>>
>>>> In fact, that will reduce atomic_check() failures with this patch because
>>>> compositor will still work the same way as it used to work before by not
>>>> trying an unsupported format on a plane.
>>>
>>> The virtual plane should support any of the formats that the backing
>>> hardware can support. If (for example) we only had RGB-only and YUV-only
>>> hardware blocks, the driver would have to construct a _superset_ of
>>> those formats. Fortunately this is not the case and VIG supports a
>>> strict superset of what DMA (or RGB) SSPP supports.
>>>
>>
>> Yes, thats why I said plane_formats_yuv is enough in my next point below
>> because Vig is super set of DMA or IOW Vig is the most feature rich plane.
>
> QCM2290 doesn't have YUV support if I'm not mistaken.
>
qcm2290_sspp has YUV support but no scaling support as per the catalog.
It uses _VIG_SBLK_NOSCALE which still has plane_formats_yuv.
>>
>>>> If one plane maps to two SSPPs, then yes we can go with the superset of
>>>> formats but that comes in a later patch right?
>>>>
>>>> 2) So even if we want to do it this way from this patch itself, I think all
>>>> you are looking for is whether there is a Vig SSPP and if so use
>>>> plane_formats_yuv. There is no need for this loop IMO.
>>>>
>>>> 3) I noticed that virt_format_list is still present in the driver. If you
>>>> are planning to not use that perhaps drop it with this series.
>>>
>>> Ack
>>>
>>>>
>>>>>>
>>>>>>
>>>>>>> + format_list = cfg->sblk->format_list;
>>>>>>> + num_formats = cfg->sblk->num_formats;
>>>>>>> + }
>>>>>>> + }
>>>>>>> +
>>>>>>> + plane = dpu_plane_init_common(dev, type, possible_crtcs,
>>>>>>> + has_inline_rotation,
>>>>>>> + format_list,
>>>>>>> + num_formats,
>>>>>>> + SSPP_NONE);
>>>>>>
>>>>>> Ok, here is the part which we were discussing in
>>>>>>
>>>>>> https://patchwork.freedesktop.org/patch/582820/?series=131109&rev=1#comment_1087370
>>>>>>
>>>>>> So yes, that part belongs to this patch.
>>>>>
>>>>> I'll check it while preparing the next iteration.
>>>>>
>>>>>>
>>>>>>> + if (IS_ERR(plane))
>>>>>>> + return plane;
>>>>>>> +
>>>>>>> + drm_plane_helper_add(plane, &dpu_plane_virtual_helper_funcs);
>>>>>>> +
>>>>>>> + DPU_DEBUG("%s created virtual id:%u\n", plane->name, plane->base.id);
>>>>>>> +
>>>>>>> return plane;
>>>>>>> }
>>>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>>>>>>> index a3ae45dc95d0..15f7d60d8b85 100644
>>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>>>>>>> @@ -30,6 +30,7 @@
>>>>>>> * @plane_fetch_bw: calculated BW per plane
>>>>>>> * @plane_clk: calculated clk per plane
>>>>>>> * @needs_dirtyfb: whether attached CRTC needs pixel data explicitly flushed
>>>>>>> + * @saved_fmt: format used by the plane's FB, saved for for virtual plane support
>>>>>>> */
>>>>>>> struct dpu_plane_state {
>>>>>>> struct drm_plane_state base;
>>>>>>> @@ -46,6 +47,8 @@ struct dpu_plane_state {
>>>>>>> u64 plane_clk;
>>>>>>> bool needs_dirtyfb;
>>>>>>> +
>>>>>>> + const struct dpu_format *saved_fmt;
>>>>>>> };
>>>>>>
>>>>>> Why is saved_fmt needed?
>>>>>>
>>>>>> The use-case which comes to my mind is lets say if we have a RGB format and
>>>>>> we need to switch to a YUV format, basically switch from DMA to ViG SSPP,
>>>>>> then yes we have to mark planes_changed as we need to switch the underlying
>>>>>> SSPP that time, but why cant we simply check that by means of a check to see
>>>>>> if the fmt is YUV and whether CSC block is present in the SSPP.
>>>>>
>>>>> Yes, correct. And vice versa, going from YUV to RGB might free the VIG
>>>>> SSPP.
>>>>>
>>>>>>
>>>>>> This will lead to dpu_crtc_reassign_planes() getting called for format
>>>>>> changes even when the new format might be available in the same SSPP.
>>>>>
>>>>> So use 'needs_vig' instead of storing the format? Sounds good to me.
>>>>>
>>>>
>>>> Yes thats the idea. Basically "needs_reassignment". You could even go from
>>>> Vig to DMA if the use-case can just use DMA to save up Vig.
>>>>
>>>> Also, do we really need to cache anything in the plane state to track this?
>>>>
>>>> If we have a function called dpu_crtc_needs_plane_reassignment() will go
>>>> through the current plane state and the current SSPP from the global state
>>>> and see if needs reassignment.
>>>
>>> No, looking at the global state won't be possible here. I'd have to lock
>>> the private object before consulting it, which might cause EDEADLOCK
>>> later on during resource reallocation. So all necessary information
>>> should be stored in the dpu_plane_state.
>>>
>>
>> But you are already calling dpu_kms_get_global_state() in
>> dpu_crtc_reassign_planes().
>
> It happens at a different point. And I'm not sure how modeset locking
> will react to an attempt to lock the private object twice.
>
hmm, I am missing the code flow a bit.
Inside drm_atomic_helper_check_planes(), we first have plane's
atomic_check followed by crtc's.
In plane's atomic_check is where we are setting planes_changed by
checking whether we need re-assignment of SSPPs.
In CRTC's atomic_check is where we have the logic to check
planes_changed and reassign the SSPPs.
We already call dpu_kms_get_global_state() in crtc atomic_check which
means we acquire the ctx for the private object.
Would it be incorrect to acquire it in plane's atomic_check?
If so, can we do one of below:
1) call drm_modeset_drop_locks() before plane's atomic_check ends. That
way within the drm_atomic_helper_check_planes(), only one ctx is tracked
at a time.
2) if (1) wont work, would dpu_kms_get_existing_global_state() help? For
that one we do not need the locking.
>>
>>>>
>>>>>>
>>>>>>> #define to_dpu_plane_state(x) \
>>>>>>> @@ -75,6 +78,16 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
>>>>>>> uint32_t pipe, enum drm_plane_type type,
>>>>>>> unsigned long possible_crtcs);
>>>>>>> +/**
>>>>>>> + * dpu_plane_init_virtual - create new dpu virtualized plane
>>>>>>> + * @dev: Pointer to DRM device
>>>>>>> + * @type: Plane type - PRIMARY/OVERLAY/CURSOR
>>>>>>> + * @possible_crtcs: bitmask of crtc that can be attached to the given pipe
>>>>>>> + */
>>>>>>> +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
>>>>>>> + enum drm_plane_type type,
>>>>>>> + unsigned long possible_crtcs);
>>>>>>> +
>>>>>>> /**
>>>>>>> * dpu_plane_color_fill - enables color fill on plane
>>>>>>> * @plane: Pointer to DRM plane object
>>>>>>> @@ -91,4 +104,10 @@ void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable);
>>>>>>> static inline void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) {}
>>>>>>> #endif
>>>>>>> +int dpu_assign_plane_resources(struct dpu_global_state *global_state,
>>>>>>> + struct drm_atomic_state *state,
>>>>>>> + struct drm_crtc *crtc,
>>>>>>> + struct drm_plane_state **states,
>>>>>>> + unsigned int num_planes);
>>>>>>> +
>>>>>>> #endif /* _DPU_PLANE_H_ */
>>>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>>>>>> index 44938ba7a2b7..7264a4d44a14 100644
>>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>>>>>> @@ -694,6 +694,83 @@ int dpu_rm_reserve(
>>>>>>> return ret;
>>>>>>> }
>>>>>>> +struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
>>>>>>> + struct dpu_global_state *global_state,
>>>>>>> + struct drm_crtc *crtc,
>>>>>>> + struct dpu_rm_sspp_requirements *reqs)
>>>>>>> +{
>>>>>>> + uint32_t crtc_id = crtc->base.id;
>>>>>>> + unsigned int weight, best_weght = UINT_MAX;
>>>>>>
>>>>>> best_weight?
>>>>>
>>>>> Yes
>>>>>
>>>>>>
>>>>>>> + struct dpu_hw_sspp *hw_sspp;
>>>>>>> + unsigned long mask = 0;
>>>>>>> + int i, best_idx = -1;
>>>>>>> +
>>>>>>> + /*
>>>>>>> + * Don't take cursor feature into consideration until there is proper support for SSPP_CURSORn.
>>>>>>> + */
>>>>>>> + mask |= BIT(DPU_SSPP_CURSOR);
>>>>>>> +
>>>>>>> + if (reqs->scale)
>>>>>>> + mask |= BIT(DPU_SSPP_SCALER_RGB) |
>>>>>>> + BIT(DPU_SSPP_SCALER_QSEED2) |
>>>>>>> + BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE);
>>>>>>> +
>>>>>>> + if (reqs->yuv)
>>>>>>> + mask |= BIT(DPU_SSPP_CSC) |
>>>>>>> + BIT(DPU_SSPP_CSC_10BIT);
>>>>>>> +
>>>>>>> + if (reqs->rot90)
>>>>>>> + mask |= BIT(DPU_SSPP_INLINE_ROTATION);
>>>>>>> +
>>>>>>> + for (i = 0; i < ARRAY_SIZE(rm->hw_sspp); i++) {
>>>>>>> + if (!rm->hw_sspp[i])
>>>>>>> + continue;
>>>>>>> +
>>>>>>> + if (global_state->sspp_to_crtc_id[i])
>>>>>>> + continue;
>>>>>>> +
>>>>>>> + hw_sspp = rm->hw_sspp[i];
>>>>>>> +
>>>>>>> + /* skip incompatible planes */
>>>>>>> + if (reqs->scale && !hw_sspp->cap->sblk->scaler_blk.len)
>>>>>>> + continue;
>>>>>>> +
>>>>>>> + if (reqs->yuv && !hw_sspp->cap->sblk->csc_blk.len)
>>>>>>> + continue;
>>>>>>> +
>>>>>>> + if (reqs->rot90 && !(hw_sspp->cap->features & DPU_SSPP_INLINE_ROTATION))
>>>>>>> + continue;
>>>>>>> +
>>>>>>> + /*
>>>>>>> + * For non-yuv, non-scaled planes prefer simple (DMA or RGB)
>>>>>>> + * plane, falling back to VIG only if there are no such planes.
>>>>>>> + *
>>>>>>> + * This way we'd leave VIG sspps to be later used for YUV formats.
>>>>>>> + */
>>>>>>> + weight = hweight64(hw_sspp->cap->features & ~mask);
>>>>>>
>>>>>> This approach is assuming that ViG feature masks are more than DMA.
>>>>>> Hence the hweight of DMA SSPP's features is less than hweight of ViG SSPPs.
>>>>>>
>>>>>> Is this really true? Because there are other bits such as DMA_SDM845_MASK
>>>>>> which might increase the hweight of DMA SSPPs
>>>>>
>>>>> Which bits are present in the DMA mask, which are not present in the VIG
>>>>> mask? Also for the older platforms there are three kinds of planes: VIG,
>>>>> DMA and RGB. The selection algorithm should not require significant
>>>>> changes to support that case.
>>>>>
>>>>
>>>> DMA_SDM845_MASK has DPU_SSPP_QOS_8LVL which is not there in VIG_MSM8998_MASK
>>>> afaict. But we really cannot be counting the number of feature bits and
>>>> going by that.
>>>
>>> MSM8998 uses DMA_MSM8998_MASK, not DMA_SDM845_MASK.
>>>
I forgot to update this point, for sm6375_sspp, it uses DMA_SDM845_MASK
for DMA and VIG_SDM845_MASK for VIG. So my point is applicable for
sm6375 atleast.
>>>> Hence, inherently, going by hweight is not right because whenever we add a
>>>> catalog change to add a new feature bit to SSPP, we have to come back here
>>>> and make sure this logic will not break.
>>>>>>
>>>>>> I would rather make it simpler.
>>>>>>
>>>>>> 1) if we need scaling || yuv, then we have to get only a Vig
>>>>>> 2) else, first try to get a DMA SSPP
>>>>>
>>>>> How would you distinguish between VIG and DMA?
>>>>>
>>>>
>>>> the type SSPP_TYPE_VIG OR SSPP_TYPE_DMA. We also have a SSPP_TYPE_RGB so
>>>> that should address your concern about the third type of plane (Vig, DMA,
>>>> RGB).
>>>
>>> I don't particularly like the idea of using type. We still need to
>>> evaluate plane's features. Consider QCM2290, where VIG planes do not
>>> support scaling.
>>>
>>> I will evaluate if I can rework this part to use type, while still
>>> checking for the feature bit. BTW: should we prefer RGB or DMA plane if
>>> all other conditions are met?
>>>
>>
>> Ok, qcm2290 really seems like an odd case but point taken.
>>
>> I am fine if it needs to be a combination of type and feature bit but
>> certainly not hweight of feature bit. If you want to use type along with
>> presence of scaler blk feature bit thats fine.
>>
>> I need to check if there is any feature loss in RGB Vs DMA. Let me check
>> and get back. This needs some history digging.
>
> Sure.
>
>>
>>>>
>>>>
>>>>>> 3) if (2) fails, we have to try to get a ViG SSPP.
>>>>>>
>>>>>> Lets be more explicit about the SSPP type here rather than using hweight.
>>>>>>
>>>>>>
>>>>>>> + if (weight < best_weght) {
>>>>>>> + best_weght = weight;
>>>>>>> + best_idx = i;
>>>>>>> + }
>>>>>>> + }
>>>>>>> +
>>>>>>> + if (best_idx < 0)
>>>>>>> + return NULL;
>>>>>>> +
>>>>>>> + global_state->sspp_to_crtc_id[best_idx] = crtc_id;
>>>>>>> +
>>>>>>> + return rm->hw_sspp[best_idx];
>>>>>>> +}
>>>>>>> +
>>>>>>> +void dpu_rm_release_all_sspp(struct dpu_global_state *global_state,
>>>>>>> + struct drm_crtc *crtc)
>>>>>>> +{
>>>>>>> + uint32_t crtc_id = crtc->base.id;
>>>>>>> +
>>>>>>> + _dpu_rm_clear_mapping(global_state->sspp_to_crtc_id,
>>>>>>> + ARRAY_SIZE(global_state->sspp_to_crtc_id), crtc_id);
>>>>>>> +}
>>>>>>> +
>>>>>>> int dpu_rm_get_assigned_resources(struct dpu_rm *rm,
>>>>>>> struct dpu_global_state *global_state, uint32_t enc_id,
>>>>>>> enum dpu_hw_blk_type type, struct dpu_hw_blk **blks, int blks_size)
>>>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
>>>>>>> index e63db8ace6b9..bf9110547385 100644
>>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
>>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
>>>>>>> @@ -37,6 +37,12 @@ struct dpu_rm {
>>>>>>> struct dpu_hw_blk *cdm_blk;
>>>>>>> };
>>>>>>> +struct dpu_rm_sspp_requirements {
>>>>>>> + bool yuv;
>>>>>>> + bool scale;
>>>>>>> + bool rot90;
>>>>>>> +};
>>>>>>> +
>>>>>>> /**
>>>>>>> * dpu_rm_init - Read hardware catalog and create reservation tracking objects
>>>>>>> * for all HW blocks.
>>>>>>> @@ -82,6 +88,28 @@ int dpu_rm_reserve(struct dpu_rm *rm,
>>>>>>> void dpu_rm_release(struct dpu_global_state *global_state,
>>>>>>> struct drm_encoder *enc);
>>>>>>> +/**
>>>>>>> + * dpu_rm_reserve_sspp - Reserve the required SSPP for the provided CRTC
>>>>>>> + * @rm: DPU Resource Manager handle
>>>>>>> + * @global_state: private global state
>>>>>>> + * @crtc: DRM CRTC handle
>>>>>>> + * @reqs: SSPP required features
>>>>>>> + */
>>>>>>> +struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
>>>>>>> + struct dpu_global_state *global_state,
>>>>>>> + struct drm_crtc *crtc,
>>>>>>> + struct dpu_rm_sspp_requirements *reqs);
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * dpu_rm_release_all_sspp - Given the CRTC, release all SSPP
>>>>>>> + * blocks previously reserved for that use case.
>>>>>>> + * @rm: DPU Resource Manager handle
>>>>>>> + * @crtc: DRM CRTC handle
>>>>>>> + * @Return: 0 on Success otherwise -ERROR
>>>>>>> + */
>>>>>>
>>>>>> This is void so does not return anything?
>>>
>>> Yes
>>>
>>>>>>
>>>>>>> +void dpu_rm_release_all_sspp(struct dpu_global_state *global_state,
>>>>>>> + struct drm_crtc *crtc);
>>>>>>> +
>>>>>>> /**
>>>>>>> * Get hw resources of the given type that are assigned to this encoder.
>>>>>>> */
>>>>>
>>>
>
>
>
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 08/13] drm/msm/dpu: add support for virtual planes
2024-06-07 23:55 ` Abhinav Kumar
@ 2024-06-08 0:57 ` Dmitry Baryshkov
2024-06-08 2:45 ` Abhinav Kumar
0 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-06-08 0:57 UTC (permalink / raw)
To: Abhinav Kumar
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On Sat, 8 Jun 2024 at 02:55, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>
>
>
> On 6/7/2024 3:26 PM, Dmitry Baryshkov wrote:
> > On Sat, 8 Jun 2024 at 00:39, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
> >>
> >>
> >>
> >> On 6/7/2024 2:10 PM, Dmitry Baryshkov wrote:
> >>> On Fri, Jun 07, 2024 at 12:22:16PM -0700, Abhinav Kumar wrote:
> >>>>
> >>>>
> >>>> On 6/7/2024 12:16 AM, Dmitry Baryshkov wrote:
> >>>>> On Thu, Jun 06, 2024 at 03:21:11PM -0700, Abhinav Kumar wrote:
> >>>>>> On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> >>>>>>> Only several SSPP blocks support such features as YUV output or scaling,
> >>>>>>> thus different DRM planes have different features. Properly utilizing
> >>>>>>> all planes requires the attention of the compositor, who should
> >>>>>>> prefer simpler planes to YUV-supporting ones. Otherwise it is very easy
> >>>>>>> to end up in a situation when all featureful planes are already
> >>>>>>> allocated for simple windows, leaving no spare plane for YUV playback.
> >>>>>>>
> >>>>>>> To solve this problem make all planes virtual. Each plane is registered
> >>>>>>> as if it supports all possible features, but then at the runtime during
> >>>>>>> the atomic_check phase the driver selects backing SSPP block for each
> >>>>>>> plane.
> >>>>>>>
> >>>>>>> Note, this does not provide support for using two different SSPP blocks
> >>>>>>> for a single plane or using two rectangles of an SSPP to drive two
> >>>>>>> planes. Each plane still gets its own SSPP and can utilize either a solo
> >>>>>>> rectangle or both multirect rectangles depending on the resolution.
> >>>>>>>
> >>>>>>> Note #2: By default support for virtual planes is turned off and the
> >>>>>>> driver still uses old code path with preallocated SSPP block for each
> >>>>>>> plane. To enable virtual planes, pass 'msm.dpu_use_virtual_planes=1'
> >>>>>>> kernel parameter.
> >>>>>>>
> >>>>>>
> >>>>>> I like the overall approach in this patch. Some comments below.
> >>>>>>
> >>>>>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> >>>>>>> ---
> >>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 50 +++++
> >>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 10 +-
> >>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 4 +
> >>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 230 +++++++++++++++++++---
> >>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 19 ++
> >>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 77 ++++++++
> >>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 28 +++
> >>>>>>> 7 files changed, 390 insertions(+), 28 deletions(-)
> >>>>>>>
> >>>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> >>>>>>> index 88c2e51ab166..794c5643584f 100644
> >>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> >>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> >>>>>>> @@ -1168,6 +1168,49 @@ static bool dpu_crtc_needs_dirtyfb(struct drm_crtc_state *cstate)
> >>>>>>> return false;
> >>>>>>> }
> >>>>>>> +static int dpu_crtc_reassign_planes(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
> >>>>>>> +{
> >>>>>>> + int total_planes = crtc->dev->mode_config.num_total_plane;
> >>>>>>> + struct drm_atomic_state *state = crtc_state->state;
> >>>>>>> + struct dpu_global_state *global_state;
> >>>>>>> + struct drm_plane_state **states;
> >>>>>>> + struct drm_plane *plane;
> >>>>>>> + int ret;
> >>>>>>> +
> >>>>>>> + global_state = dpu_kms_get_global_state(crtc_state->state);
> >>>>>>> + if (IS_ERR(global_state))
> >>>>>>> + return PTR_ERR(global_state);
> >>>>>>> +
> >>>>>>> + dpu_rm_release_all_sspp(global_state, crtc);
> >>>>>>> +
> >>>>>>
> >>>>>> Do we need to call dpu_rm_release_all_sspp() even in the
> >>>>>> _dpu_plane_atomic_disable()?
> >>>>>
> >>>>> It allows the driver to optimize the usage of the SSPP rectangles.
> >>>>>
> >>>>
> >>>> No, what I meant was that we should call dpu_rm_release_all_sspp() in
> >>>> dpu_plane_atomic_update() as well because in the atomic_check() path where
> >>>> its called today, its being called only for zpos_changed and planes_changed
> >>>> but during disable we must call this for sure.
> >>>
> >>> No. the dpu_rm_release_all_sspp() should only be called during check.
> >>> When dpu_plane_atomic_update() is called, the state should already be
> >>> finalised. The atomic_check() callback is called when a plane is going
> >>> to be disabled.
> >>>
> >>
> >> atomic_check() will be called when plane is disabled but
> >> dpu_rm_release_all_sspp() may not be called as it is protected by
> >> zpos_changed and planes_changed. OR you need to add a !visible check
> >> here to call dpu_rm_release_all_sspp() that time. Thats whay I wrote
> >> previously.
> >
> > Unless I miss something, if a plane gets disabled, then obviously
> > planes_changed is true.
> >
> > [trimmed]
> >
>
> Do you mean DRM fwk sets planes_changed correctly for this case?
>
> Currently we have
>
> if (!new_state->visible) {
> _dpu_plane_atomic_disable(plane);
> } else {
> dpu_plane_sspp_atomic_update(plane);
> }
>
> So I wanted to ensure that when plane gets disabled, its SSPP is freed
> too. If this is confirmed, I do not have any concerns.
This is the atomic_update() path, not the atomic_check()
>
> >>
> >>>>>>> @@ -1486,7 +1593,7 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
> >>>>>>> supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
> >>>>>>> - if (pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION))
> >>>>>>> + if (inline_rotation)
> >>>>>>> supported_rotations |= DRM_MODE_ROTATE_MASK;
> >>>>>>> drm_plane_create_rotation_property(plane,
> >>>>>>> @@ -1494,10 +1601,81 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
> >>>>>>> drm_plane_enable_fb_damage_clips(plane);
> >>>>>>> - /* success! finalize initialization */
> >>>>>>> + DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
> >>>>>>> + pipe, plane->base.id);
> >>>>>>> + return plane;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +struct drm_plane *dpu_plane_init(struct drm_device *dev,
> >>>>>>> + uint32_t pipe, enum drm_plane_type type,
> >>>>>>> + unsigned long possible_crtcs)
> >>>>>>> +{
> >>>>>>> + struct drm_plane *plane = NULL;
> >>>>>>> + struct msm_drm_private *priv = dev->dev_private;
> >>>>>>> + struct dpu_kms *kms = to_dpu_kms(priv->kms);
> >>>>>>> + struct dpu_hw_sspp *pipe_hw;
> >>>>>>> +
> >>>>>>> + /* initialize underlying h/w driver */
> >>>>>>> + pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);
> >>>>>>> + if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {
> >>>>>>> + DPU_ERROR("[%u]SSPP is invalid\n", pipe);
> >>>>>>> + return ERR_PTR(-EINVAL);
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> +
> >>>>>>> + plane = dpu_plane_init_common(dev, type, possible_crtcs,
> >>>>>>> + pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION),
> >>>>>>> + pipe_hw->cap->sblk->format_list,
> >>>>>>> + pipe_hw->cap->sblk->num_formats,
> >>>>>>> + pipe);
> >>>>>>> + if (IS_ERR(plane))
> >>>>>>> + return plane;
> >>>>>>> +
> >>>>>>> drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
> >>>>>>> DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
> >>>>>>> pipe, plane->base.id);
> >>>>>>> +
> >>>>>>> + return plane;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
> >>>>>>> + enum drm_plane_type type,
> >>>>>>> + unsigned long possible_crtcs)
> >>>>>>> +{
> >>>>>>> + struct drm_plane *plane = NULL;
> >>>>>>> + struct msm_drm_private *priv = dev->dev_private;
> >>>>>>> + struct dpu_kms *kms = to_dpu_kms(priv->kms);
> >>>>>>> + bool has_inline_rotation = false;
> >>>>>>> + const u32 *format_list = NULL;
> >>>>>>> + u32 num_formats = 0;
> >>>>>>> + int i;
> >>>>>>> +
> >>>>>>> + /* Determine the largest configuration that we can implement */
> >>>>>>> + for (i = 0; i < kms->catalog->sspp_count; i++) {
> >>>>>>> + const struct dpu_sspp_cfg *cfg = &kms->catalog->sspp[i];
> >>>>>>> +
> >>>>>>> + if (test_bit(DPU_SSPP_INLINE_ROTATION, &cfg->features))
> >>>>>>> + has_inline_rotation = true;
> >>>>>>> +
> >>>>>>> + if (!format_list ||
> >>>>>>> + cfg->sblk->csc_blk.len) {
> >>>>>>
> >>>>>> But format_list is being assigned to NULL just a few lines above. Why is
> >>>>>> this check needed?
> >>>>>
> >>>>> It was assigned before the loop.
> >>>>>
> >>>>
> >>>> Yes, I got this part but missed on why we needed the loop at all.
> >>>
> >>> Which set of formats should the virtual plane use?
> >>>
> >>>>>>
> >>>>>> I dont get why this part can also goto dpu_plane_init_common() as it looks
> >>>>>> identical to me.
> >>>>>
> >>>>> And it is not. For the non-virtual case there is no loop around formats
> >>>>> list assignment.
> >>>>>
> >>>>
> >>>> Ah okay, I misunderstood the logic. After reading the comment above the loop
> >>>> I get what you are trying to do here.
> >>>>
> >>>> But I dont get why you really need to do that?
> >>>>
> >>>> 1) In this patch the relationship between virtual plane and SSPP is still
> >>>> 1:1 so what is wrong to retain the sspp's actual format for the plane rather
> >>>> than picking the best format (you are targetting Vig SSPP)
> >>>
> >>> No. With this patch there is no 1:1 relationship. The RM will select the
> >>> SSPP that suits the requirements (YUV, scaling, rotation, etc).
> >>>
> >>
> >> Yes but there is always only one SSPP for one plane is what I meant.
> >> That does not change till the next patch.
> >>
> >> In that sense, I dont see why you need to expose the superset of formats.
> >
> > Let me please repeat my question: what set of formats should be used
> > for plane init?
> >
>
> So, my point here was that in the loop, in this patch, we create one
> plane for one SSPP, why dont we just use the same SSPP's format for that
> plane.
Which SSPP? There is no SSPP attached to a virtual plane.
>
> In the next patch, when the same plane can attach to two different
> SSPPs, we will use the superset of the SSPPs. IOW, do we need the
> superset in this patch itself?
>
> >>
> >>>> In fact, that will reduce atomic_check() failures with this patch because
> >>>> compositor will still work the same way as it used to work before by not
> >>>> trying an unsupported format on a plane.
> >>>
> >>> The virtual plane should support any of the formats that the backing
> >>> hardware can support. If (for example) we only had RGB-only and YUV-only
> >>> hardware blocks, the driver would have to construct a _superset_ of
> >>> those formats. Fortunately this is not the case and VIG supports a
> >>> strict superset of what DMA (or RGB) SSPP supports.
> >>>
> >>
> >> Yes, thats why I said plane_formats_yuv is enough in my next point below
> >> because Vig is super set of DMA or IOW Vig is the most feature rich plane.
> >
> > QCM2290 doesn't have YUV support if I'm not mistaken.
> >
>
> qcm2290_sspp has YUV support but no scaling support as per the catalog.
> It uses _VIG_SBLK_NOSCALE which still has plane_formats_yuv.
I'll check it on the real hw. I remember that I had questions regarding it.
>
> >>
> >>>> If one plane maps to two SSPPs, then yes we can go with the superset of
> >>>> formats but that comes in a later patch right?
> >>>>
> >>>> 2) So even if we want to do it this way from this patch itself, I think all
> >>>> you are looking for is whether there is a Vig SSPP and if so use
> >>>> plane_formats_yuv. There is no need for this loop IMO.
> >>>>
> >>>> 3) I noticed that virt_format_list is still present in the driver. If you
> >>>> are planning to not use that perhaps drop it with this series.
> >>>
> >>> Ack
> >>>
> >>>>
> >>>>>>
> >>>>>>
> >>>>>>> + format_list = cfg->sblk->format_list;
> >>>>>>> + num_formats = cfg->sblk->num_formats;
> >>>>>>> + }
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + plane = dpu_plane_init_common(dev, type, possible_crtcs,
> >>>>>>> + has_inline_rotation,
> >>>>>>> + format_list,
> >>>>>>> + num_formats,
> >>>>>>> + SSPP_NONE);
> >>>>>>
> >>>>>> Ok, here is the part which we were discussing in
> >>>>>>
> >>>>>> https://patchwork.freedesktop.org/patch/582820/?series=131109&rev=1#comment_1087370
> >>>>>>
> >>>>>> So yes, that part belongs to this patch.
> >>>>>
> >>>>> I'll check it while preparing the next iteration.
> >>>>>
> >>>>>>
> >>>>>>> + if (IS_ERR(plane))
> >>>>>>> + return plane;
> >>>>>>> +
> >>>>>>> + drm_plane_helper_add(plane, &dpu_plane_virtual_helper_funcs);
> >>>>>>> +
> >>>>>>> + DPU_DEBUG("%s created virtual id:%u\n", plane->name, plane->base.id);
> >>>>>>> +
> >>>>>>> return plane;
> >>>>>>> }
> >>>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> >>>>>>> index a3ae45dc95d0..15f7d60d8b85 100644
> >>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> >>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> >>>>>>> @@ -30,6 +30,7 @@
> >>>>>>> * @plane_fetch_bw: calculated BW per plane
> >>>>>>> * @plane_clk: calculated clk per plane
> >>>>>>> * @needs_dirtyfb: whether attached CRTC needs pixel data explicitly flushed
> >>>>>>> + * @saved_fmt: format used by the plane's FB, saved for for virtual plane support
> >>>>>>> */
> >>>>>>> struct dpu_plane_state {
> >>>>>>> struct drm_plane_state base;
> >>>>>>> @@ -46,6 +47,8 @@ struct dpu_plane_state {
> >>>>>>> u64 plane_clk;
> >>>>>>> bool needs_dirtyfb;
> >>>>>>> +
> >>>>>>> + const struct dpu_format *saved_fmt;
> >>>>>>> };
> >>>>>>
> >>>>>> Why is saved_fmt needed?
> >>>>>>
> >>>>>> The use-case which comes to my mind is lets say if we have a RGB format and
> >>>>>> we need to switch to a YUV format, basically switch from DMA to ViG SSPP,
> >>>>>> then yes we have to mark planes_changed as we need to switch the underlying
> >>>>>> SSPP that time, but why cant we simply check that by means of a check to see
> >>>>>> if the fmt is YUV and whether CSC block is present in the SSPP.
> >>>>>
> >>>>> Yes, correct. And vice versa, going from YUV to RGB might free the VIG
> >>>>> SSPP.
> >>>>>
> >>>>>>
> >>>>>> This will lead to dpu_crtc_reassign_planes() getting called for format
> >>>>>> changes even when the new format might be available in the same SSPP.
> >>>>>
> >>>>> So use 'needs_vig' instead of storing the format? Sounds good to me.
> >>>>>
> >>>>
> >>>> Yes thats the idea. Basically "needs_reassignment". You could even go from
> >>>> Vig to DMA if the use-case can just use DMA to save up Vig.
> >>>>
> >>>> Also, do we really need to cache anything in the plane state to track this?
> >>>>
> >>>> If we have a function called dpu_crtc_needs_plane_reassignment() will go
> >>>> through the current plane state and the current SSPP from the global state
> >>>> and see if needs reassignment.
> >>>
> >>> No, looking at the global state won't be possible here. I'd have to lock
> >>> the private object before consulting it, which might cause EDEADLOCK
> >>> later on during resource reallocation. So all necessary information
> >>> should be stored in the dpu_plane_state.
> >>>
> >>
> >> But you are already calling dpu_kms_get_global_state() in
> >> dpu_crtc_reassign_planes().
> >
> > It happens at a different point. And I'm not sure how modeset locking
> > will react to an attempt to lock the private object twice.
> >
>
> hmm, I am missing the code flow a bit.
>
> Inside drm_atomic_helper_check_planes(), we first have plane's
> atomic_check followed by crtc's.
>
> In plane's atomic_check is where we are setting planes_changed by
> checking whether we need re-assignment of SSPPs.
>
> In CRTC's atomic_check is where we have the logic to check
> planes_changed and reassign the SSPPs.
>
> We already call dpu_kms_get_global_state() in crtc atomic_check which
> means we acquire the ctx for the private object.
>
> Would it be incorrect to acquire it in plane's atomic_check?
>
> If so, can we do one of below:
>
> 1) call drm_modeset_drop_locks() before plane's atomic_check ends. That
> way within the drm_atomic_helper_check_planes(), only one ctx is tracked
> at a time.
No, if I understand it correctly, this would drop all lock, so all the
objects are unlocked.
>
> 2) if (1) wont work, would dpu_kms_get_existing_global_state() help? For
> that one we do not need the locking.
I'll check whether this works as expected.
But really I don't see a problem that you are trying to solve. It is
too early to run SSPP allocation before dpu_crtc_atomic_check(). We
need a set of all the plane states that are used by the CRTC. Even
though it is not needed for this patch (it can work with just single
plane state), it doesn't make sense to rewire that again, within the
same patchset.
>
>
> >>
> >>>>
> >>>>>>
> >>>>>>> #define to_dpu_plane_state(x) \
> >>>>>>> @@ -75,6 +78,16 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
> >>>>>>> uint32_t pipe, enum drm_plane_type type,
> >>>>>>> unsigned long possible_crtcs);
> >>>>>>> +/**
> >>>>>>> + * dpu_plane_init_virtual - create new dpu virtualized plane
> >>>>>>> + * @dev: Pointer to DRM device
> >>>>>>> + * @type: Plane type - PRIMARY/OVERLAY/CURSOR
> >>>>>>> + * @possible_crtcs: bitmask of crtc that can be attached to the given pipe
> >>>>>>> + */
> >>>>>>> +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
> >>>>>>> + enum drm_plane_type type,
> >>>>>>> + unsigned long possible_crtcs);
> >>>>>>> +
> >>>>>>> /**
> >>>>>>> * dpu_plane_color_fill - enables color fill on plane
> >>>>>>> * @plane: Pointer to DRM plane object
> >>>>>>> @@ -91,4 +104,10 @@ void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable);
> >>>>>>> static inline void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) {}
> >>>>>>> #endif
> >>>>>>> +int dpu_assign_plane_resources(struct dpu_global_state *global_state,
> >>>>>>> + struct drm_atomic_state *state,
> >>>>>>> + struct drm_crtc *crtc,
> >>>>>>> + struct drm_plane_state **states,
> >>>>>>> + unsigned int num_planes);
> >>>>>>> +
> >>>>>>> #endif /* _DPU_PLANE_H_ */
> >>>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> >>>>>>> index 44938ba7a2b7..7264a4d44a14 100644
> >>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> >>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> >>>>>>> @@ -694,6 +694,83 @@ int dpu_rm_reserve(
> >>>>>>> return ret;
> >>>>>>> }
> >>>>>>> +struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
> >>>>>>> + struct dpu_global_state *global_state,
> >>>>>>> + struct drm_crtc *crtc,
> >>>>>>> + struct dpu_rm_sspp_requirements *reqs)
> >>>>>>> +{
> >>>>>>> + uint32_t crtc_id = crtc->base.id;
> >>>>>>> + unsigned int weight, best_weght = UINT_MAX;
> >>>>>>
> >>>>>> best_weight?
> >>>>>
> >>>>> Yes
> >>>>>
> >>>>>>
> >>>>>>> + struct dpu_hw_sspp *hw_sspp;
> >>>>>>> + unsigned long mask = 0;
> >>>>>>> + int i, best_idx = -1;
> >>>>>>> +
> >>>>>>> + /*
> >>>>>>> + * Don't take cursor feature into consideration until there is proper support for SSPP_CURSORn.
> >>>>>>> + */
> >>>>>>> + mask |= BIT(DPU_SSPP_CURSOR);
> >>>>>>> +
> >>>>>>> + if (reqs->scale)
> >>>>>>> + mask |= BIT(DPU_SSPP_SCALER_RGB) |
> >>>>>>> + BIT(DPU_SSPP_SCALER_QSEED2) |
> >>>>>>> + BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE);
> >>>>>>> +
> >>>>>>> + if (reqs->yuv)
> >>>>>>> + mask |= BIT(DPU_SSPP_CSC) |
> >>>>>>> + BIT(DPU_SSPP_CSC_10BIT);
> >>>>>>> +
> >>>>>>> + if (reqs->rot90)
> >>>>>>> + mask |= BIT(DPU_SSPP_INLINE_ROTATION);
> >>>>>>> +
> >>>>>>> + for (i = 0; i < ARRAY_SIZE(rm->hw_sspp); i++) {
> >>>>>>> + if (!rm->hw_sspp[i])
> >>>>>>> + continue;
> >>>>>>> +
> >>>>>>> + if (global_state->sspp_to_crtc_id[i])
> >>>>>>> + continue;
> >>>>>>> +
> >>>>>>> + hw_sspp = rm->hw_sspp[i];
> >>>>>>> +
> >>>>>>> + /* skip incompatible planes */
> >>>>>>> + if (reqs->scale && !hw_sspp->cap->sblk->scaler_blk.len)
> >>>>>>> + continue;
> >>>>>>> +
> >>>>>>> + if (reqs->yuv && !hw_sspp->cap->sblk->csc_blk.len)
> >>>>>>> + continue;
> >>>>>>> +
> >>>>>>> + if (reqs->rot90 && !(hw_sspp->cap->features & DPU_SSPP_INLINE_ROTATION))
> >>>>>>> + continue;
> >>>>>>> +
> >>>>>>> + /*
> >>>>>>> + * For non-yuv, non-scaled planes prefer simple (DMA or RGB)
> >>>>>>> + * plane, falling back to VIG only if there are no such planes.
> >>>>>>> + *
> >>>>>>> + * This way we'd leave VIG sspps to be later used for YUV formats.
> >>>>>>> + */
> >>>>>>> + weight = hweight64(hw_sspp->cap->features & ~mask);
> >>>>>>
> >>>>>> This approach is assuming that ViG feature masks are more than DMA.
> >>>>>> Hence the hweight of DMA SSPP's features is less than hweight of ViG SSPPs.
> >>>>>>
> >>>>>> Is this really true? Because there are other bits such as DMA_SDM845_MASK
> >>>>>> which might increase the hweight of DMA SSPPs
> >>>>>
> >>>>> Which bits are present in the DMA mask, which are not present in the VIG
> >>>>> mask? Also for the older platforms there are three kinds of planes: VIG,
> >>>>> DMA and RGB. The selection algorithm should not require significant
> >>>>> changes to support that case.
> >>>>>
> >>>>
> >>>> DMA_SDM845_MASK has DPU_SSPP_QOS_8LVL which is not there in VIG_MSM8998_MASK
> >>>> afaict. But we really cannot be counting the number of feature bits and
> >>>> going by that.
> >>>
> >>> MSM8998 uses DMA_MSM8998_MASK, not DMA_SDM845_MASK.
> >>>
>
> I forgot to update this point, for sm6375_sspp, it uses DMA_SDM845_MASK
> for DMA and VIG_SDM845_MASK for VIG. So my point is applicable for
> sm6375 atleast.
DPU_SSPP_QOS_8LVL is enabled in both VIG_SDM845_MASK and DMA_SDM845_MASK
> >>>> Hence, inherently, going by hweight is not right because whenever we add a
> >>>> catalog change to add a new feature bit to SSPP, we have to come back here
> >>>> and make sure this logic will not break.
> >>>>>>
> >>>>>> I would rather make it simpler.
> >>>>>>
> >>>>>> 1) if we need scaling || yuv, then we have to get only a Vig
> >>>>>> 2) else, first try to get a DMA SSPP
> >>>>>
> >>>>> How would you distinguish between VIG and DMA?
> >>>>>
> >>>>
> >>>> the type SSPP_TYPE_VIG OR SSPP_TYPE_DMA. We also have a SSPP_TYPE_RGB so
> >>>> that should address your concern about the third type of plane (Vig, DMA,
> >>>> RGB).
> >>>
> >>> I don't particularly like the idea of using type. We still need to
> >>> evaluate plane's features. Consider QCM2290, where VIG planes do not
> >>> support scaling.
> >>>
> >>> I will evaluate if I can rework this part to use type, while still
> >>> checking for the feature bit. BTW: should we prefer RGB or DMA plane if
> >>> all other conditions are met?
> >>>
> >>
> >> Ok, qcm2290 really seems like an odd case but point taken.
> >>
> >> I am fine if it needs to be a combination of type and feature bit but
> >> certainly not hweight of feature bit. If you want to use type along with
> >> presence of scaler blk feature bit thats fine.
> >>
> >> I need to check if there is any feature loss in RGB Vs DMA. Let me check
> >> and get back. This needs some history digging.
> >
> > Sure.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 08/13] drm/msm/dpu: add support for virtual planes
2024-06-08 0:57 ` Dmitry Baryshkov
@ 2024-06-08 2:45 ` Abhinav Kumar
2024-06-10 21:01 ` Abhinav Kumar
0 siblings, 1 reply; 50+ messages in thread
From: Abhinav Kumar @ 2024-06-08 2:45 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On 6/7/2024 5:57 PM, Dmitry Baryshkov wrote:
> On Sat, 8 Jun 2024 at 02:55, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>>
>>
>>
>> On 6/7/2024 3:26 PM, Dmitry Baryshkov wrote:
>>> On Sat, 8 Jun 2024 at 00:39, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>>>>
>>>>
>>>>
>>>> On 6/7/2024 2:10 PM, Dmitry Baryshkov wrote:
>>>>> On Fri, Jun 07, 2024 at 12:22:16PM -0700, Abhinav Kumar wrote:
>>>>>>
>>>>>>
>>>>>> On 6/7/2024 12:16 AM, Dmitry Baryshkov wrote:
>>>>>>> On Thu, Jun 06, 2024 at 03:21:11PM -0700, Abhinav Kumar wrote:
>>>>>>>> On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
>>>>>>>>> Only several SSPP blocks support such features as YUV output or scaling,
>>>>>>>>> thus different DRM planes have different features. Properly utilizing
>>>>>>>>> all planes requires the attention of the compositor, who should
>>>>>>>>> prefer simpler planes to YUV-supporting ones. Otherwise it is very easy
>>>>>>>>> to end up in a situation when all featureful planes are already
>>>>>>>>> allocated for simple windows, leaving no spare plane for YUV playback.
>>>>>>>>>
>>>>>>>>> To solve this problem make all planes virtual. Each plane is registered
>>>>>>>>> as if it supports all possible features, but then at the runtime during
>>>>>>>>> the atomic_check phase the driver selects backing SSPP block for each
>>>>>>>>> plane.
>>>>>>>>>
>>>>>>>>> Note, this does not provide support for using two different SSPP blocks
>>>>>>>>> for a single plane or using two rectangles of an SSPP to drive two
>>>>>>>>> planes. Each plane still gets its own SSPP and can utilize either a solo
>>>>>>>>> rectangle or both multirect rectangles depending on the resolution.
>>>>>>>>>
>>>>>>>>> Note #2: By default support for virtual planes is turned off and the
>>>>>>>>> driver still uses old code path with preallocated SSPP block for each
>>>>>>>>> plane. To enable virtual planes, pass 'msm.dpu_use_virtual_planes=1'
>>>>>>>>> kernel parameter.
>>>>>>>>>
>>>>>>>>
>>>>>>>> I like the overall approach in this patch. Some comments below.
>>>>>>>>
>>>>>>>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>>>>>>>> ---
>>>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 50 +++++
>>>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 10 +-
>>>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 4 +
>>>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 230 +++++++++++++++++++---
>>>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 19 ++
>>>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 77 ++++++++
>>>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 28 +++
>>>>>>>>> 7 files changed, 390 insertions(+), 28 deletions(-)
>>>>>>>>>
>>>>>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>>>>>> index 88c2e51ab166..794c5643584f 100644
>>>>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>>>>>> @@ -1168,6 +1168,49 @@ static bool dpu_crtc_needs_dirtyfb(struct drm_crtc_state *cstate)
>>>>>>>>> return false;
>>>>>>>>> }
>>>>>>>>> +static int dpu_crtc_reassign_planes(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
>>>>>>>>> +{
>>>>>>>>> + int total_planes = crtc->dev->mode_config.num_total_plane;
>>>>>>>>> + struct drm_atomic_state *state = crtc_state->state;
>>>>>>>>> + struct dpu_global_state *global_state;
>>>>>>>>> + struct drm_plane_state **states;
>>>>>>>>> + struct drm_plane *plane;
>>>>>>>>> + int ret;
>>>>>>>>> +
>>>>>>>>> + global_state = dpu_kms_get_global_state(crtc_state->state);
>>>>>>>>> + if (IS_ERR(global_state))
>>>>>>>>> + return PTR_ERR(global_state);
>>>>>>>>> +
>>>>>>>>> + dpu_rm_release_all_sspp(global_state, crtc);
>>>>>>>>> +
>>>>>>>>
>>>>>>>> Do we need to call dpu_rm_release_all_sspp() even in the
>>>>>>>> _dpu_plane_atomic_disable()?
>>>>>>>
>>>>>>> It allows the driver to optimize the usage of the SSPP rectangles.
>>>>>>>
>>>>>>
>>>>>> No, what I meant was that we should call dpu_rm_release_all_sspp() in
>>>>>> dpu_plane_atomic_update() as well because in the atomic_check() path where
>>>>>> its called today, its being called only for zpos_changed and planes_changed
>>>>>> but during disable we must call this for sure.
>>>>>
>>>>> No. the dpu_rm_release_all_sspp() should only be called during check.
>>>>> When dpu_plane_atomic_update() is called, the state should already be
>>>>> finalised. The atomic_check() callback is called when a plane is going
>>>>> to be disabled.
>>>>>
>>>>
>>>> atomic_check() will be called when plane is disabled but
>>>> dpu_rm_release_all_sspp() may not be called as it is protected by
>>>> zpos_changed and planes_changed. OR you need to add a !visible check
>>>> here to call dpu_rm_release_all_sspp() that time. Thats whay I wrote
>>>> previously.
>>>
>>> Unless I miss something, if a plane gets disabled, then obviously
>>> planes_changed is true.
>>>
>>> [trimmed]
>>>
>>
>> Do you mean DRM fwk sets planes_changed correctly for this case?
>>
>> Currently we have
>>
>> if (!new_state->visible) {
>> _dpu_plane_atomic_disable(plane);
>> } else {
>> dpu_plane_sspp_atomic_update(plane);
>> }
>>
>> So I wanted to ensure that when plane gets disabled, its SSPP is freed
>> too. If this is confirmed, I do not have any concerns.
>
> This is the atomic_update() path, not the atomic_check()
>
Yes, I am aware.
Let me clarify my question here once again.
1) dpu_rm_release_all_sspp() gets called only in atomic_check() when
either planes_changed or zpos_changed is set
2) But even in _dpu_plane_atomic_disable(), we should call
dpu_rm_release_all_sspp() unconditionally. So for this, as you wrote,
the corresponding atomic_check() call of _dpu_plane_atomic_disable() is
supposed to do this. atomic_check() checks planes_changed and
zpos_changed but not !visible before calling dpu_rm_release_all_sspp().
Will planes_changed be set even when !visible?
I am trying to make sure that dpu_rm_release_all_sspp() will get called
for the _dpu_plane_atomic_disable(). Thats all.
>>
>>>>
>>>>>>>>> @@ -1486,7 +1593,7 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
>>>>>>>>> supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
>>>>>>>>> - if (pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION))
>>>>>>>>> + if (inline_rotation)
>>>>>>>>> supported_rotations |= DRM_MODE_ROTATE_MASK;
>>>>>>>>> drm_plane_create_rotation_property(plane,
>>>>>>>>> @@ -1494,10 +1601,81 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
>>>>>>>>> drm_plane_enable_fb_damage_clips(plane);
>>>>>>>>> - /* success! finalize initialization */
>>>>>>>>> + DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
>>>>>>>>> + pipe, plane->base.id);
>>>>>>>>> + return plane;
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +struct drm_plane *dpu_plane_init(struct drm_device *dev,
>>>>>>>>> + uint32_t pipe, enum drm_plane_type type,
>>>>>>>>> + unsigned long possible_crtcs)
>>>>>>>>> +{
>>>>>>>>> + struct drm_plane *plane = NULL;
>>>>>>>>> + struct msm_drm_private *priv = dev->dev_private;
>>>>>>>>> + struct dpu_kms *kms = to_dpu_kms(priv->kms);
>>>>>>>>> + struct dpu_hw_sspp *pipe_hw;
>>>>>>>>> +
>>>>>>>>> + /* initialize underlying h/w driver */
>>>>>>>>> + pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);
>>>>>>>>> + if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {
>>>>>>>>> + DPU_ERROR("[%u]SSPP is invalid\n", pipe);
>>>>>>>>> + return ERR_PTR(-EINVAL);
>>>>>>>>> + }
>>>>>>>>> +
>>>>>>>>> +
>>>>>>>>> + plane = dpu_plane_init_common(dev, type, possible_crtcs,
>>>>>>>>> + pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION),
>>>>>>>>> + pipe_hw->cap->sblk->format_list,
>>>>>>>>> + pipe_hw->cap->sblk->num_formats,
>>>>>>>>> + pipe);
>>>>>>>>> + if (IS_ERR(plane))
>>>>>>>>> + return plane;
>>>>>>>>> +
>>>>>>>>> drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
>>>>>>>>> DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
>>>>>>>>> pipe, plane->base.id);
>>>>>>>>> +
>>>>>>>>> + return plane;
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
>>>>>>>>> + enum drm_plane_type type,
>>>>>>>>> + unsigned long possible_crtcs)
>>>>>>>>> +{
>>>>>>>>> + struct drm_plane *plane = NULL;
>>>>>>>>> + struct msm_drm_private *priv = dev->dev_private;
>>>>>>>>> + struct dpu_kms *kms = to_dpu_kms(priv->kms);
>>>>>>>>> + bool has_inline_rotation = false;
>>>>>>>>> + const u32 *format_list = NULL;
>>>>>>>>> + u32 num_formats = 0;
>>>>>>>>> + int i;
>>>>>>>>> +
>>>>>>>>> + /* Determine the largest configuration that we can implement */
>>>>>>>>> + for (i = 0; i < kms->catalog->sspp_count; i++) {
>>>>>>>>> + const struct dpu_sspp_cfg *cfg = &kms->catalog->sspp[i];
>>>>>>>>> +
>>>>>>>>> + if (test_bit(DPU_SSPP_INLINE_ROTATION, &cfg->features))
>>>>>>>>> + has_inline_rotation = true;
>>>>>>>>> +
>>>>>>>>> + if (!format_list ||
>>>>>>>>> + cfg->sblk->csc_blk.len) {
>>>>>>>>
>>>>>>>> But format_list is being assigned to NULL just a few lines above. Why is
>>>>>>>> this check needed?
>>>>>>>
>>>>>>> It was assigned before the loop.
>>>>>>>
>>>>>>
>>>>>> Yes, I got this part but missed on why we needed the loop at all.
>>>>>
>>>>> Which set of formats should the virtual plane use?
>>>>>
>>>>>>>>
>>>>>>>> I dont get why this part can also goto dpu_plane_init_common() as it looks
>>>>>>>> identical to me.
>>>>>>>
>>>>>>> And it is not. For the non-virtual case there is no loop around formats
>>>>>>> list assignment.
>>>>>>>
>>>>>>
>>>>>> Ah okay, I misunderstood the logic. After reading the comment above the loop
>>>>>> I get what you are trying to do here.
>>>>>>
>>>>>> But I dont get why you really need to do that?
>>>>>>
>>>>>> 1) In this patch the relationship between virtual plane and SSPP is still
>>>>>> 1:1 so what is wrong to retain the sspp's actual format for the plane rather
>>>>>> than picking the best format (you are targetting Vig SSPP)
>>>>>
>>>>> No. With this patch there is no 1:1 relationship. The RM will select the
>>>>> SSPP that suits the requirements (YUV, scaling, rotation, etc).
>>>>>
>>>>
>>>> Yes but there is always only one SSPP for one plane is what I meant.
>>>> That does not change till the next patch.
>>>>
>>>> In that sense, I dont see why you need to expose the superset of formats.
>>>
>>> Let me please repeat my question: what set of formats should be used
>>> for plane init?
>>>
>>
>> So, my point here was that in the loop, in this patch, we create one
>> plane for one SSPP, why dont we just use the same SSPP's format for that
>> plane.
>
> Which SSPP? There is no SSPP attached to a virtual plane.
>
dpu_plane_init_virtual() gets called for each SSPP of the catalog in
this patchset just like dpu_plane_init().
The only difference is dpu_plane_init() also passes the pipe but
dpu_plane_init_virtual() does not.
Would it be incorrect to also pass along the sspp's fmt list (from the
catalog->sspp loop) to dpu_plane_init_virtual() instead of the superset?
>>
>> In the next patch, when the same plane can attach to two different
>> SSPPs, we will use the superset of the SSPPs. IOW, do we need the
>> superset in this patch itself?
>>
>>>>
>>>>>> In fact, that will reduce atomic_check() failures with this patch because
>>>>>> compositor will still work the same way as it used to work before by not
>>>>>> trying an unsupported format on a plane.
>>>>>
>>>>> The virtual plane should support any of the formats that the backing
>>>>> hardware can support. If (for example) we only had RGB-only and YUV-only
>>>>> hardware blocks, the driver would have to construct a _superset_ of
>>>>> those formats. Fortunately this is not the case and VIG supports a
>>>>> strict superset of what DMA (or RGB) SSPP supports.
>>>>>
>>>>
>>>> Yes, thats why I said plane_formats_yuv is enough in my next point below
>>>> because Vig is super set of DMA or IOW Vig is the most feature rich plane.
>>>
>>> QCM2290 doesn't have YUV support if I'm not mistaken.
>>>
>>
>> qcm2290_sspp has YUV support but no scaling support as per the catalog.
>> It uses _VIG_SBLK_NOSCALE which still has plane_formats_yuv.
>
> I'll check it on the real hw. I remember that I had questions regarding it.
>
>>
>>>>
>>>>>> If one plane maps to two SSPPs, then yes we can go with the superset of
>>>>>> formats but that comes in a later patch right?
>>>>>>
>>>>>> 2) So even if we want to do it this way from this patch itself, I think all
>>>>>> you are looking for is whether there is a Vig SSPP and if so use
>>>>>> plane_formats_yuv. There is no need for this loop IMO.
>>>>>>
>>>>>> 3) I noticed that virt_format_list is still present in the driver. If you
>>>>>> are planning to not use that perhaps drop it with this series.
>>>>>
>>>>> Ack
>>>>>
>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>> + format_list = cfg->sblk->format_list;
>>>>>>>>> + num_formats = cfg->sblk->num_formats;
>>>>>>>>> + }
>>>>>>>>> + }
>>>>>>>>> +
>>>>>>>>> + plane = dpu_plane_init_common(dev, type, possible_crtcs,
>>>>>>>>> + has_inline_rotation,
>>>>>>>>> + format_list,
>>>>>>>>> + num_formats,
>>>>>>>>> + SSPP_NONE);
>>>>>>>>
>>>>>>>> Ok, here is the part which we were discussing in
>>>>>>>>
>>>>>>>> https://patchwork.freedesktop.org/patch/582820/?series=131109&rev=1#comment_1087370
>>>>>>>>
>>>>>>>> So yes, that part belongs to this patch.
>>>>>>>
>>>>>>> I'll check it while preparing the next iteration.
>>>>>>>
>>>>>>>>
>>>>>>>>> + if (IS_ERR(plane))
>>>>>>>>> + return plane;
>>>>>>>>> +
>>>>>>>>> + drm_plane_helper_add(plane, &dpu_plane_virtual_helper_funcs);
>>>>>>>>> +
>>>>>>>>> + DPU_DEBUG("%s created virtual id:%u\n", plane->name, plane->base.id);
>>>>>>>>> +
>>>>>>>>> return plane;
>>>>>>>>> }
>>>>>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>>>>>>>>> index a3ae45dc95d0..15f7d60d8b85 100644
>>>>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>>>>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>>>>>>>>> @@ -30,6 +30,7 @@
>>>>>>>>> * @plane_fetch_bw: calculated BW per plane
>>>>>>>>> * @plane_clk: calculated clk per plane
>>>>>>>>> * @needs_dirtyfb: whether attached CRTC needs pixel data explicitly flushed
>>>>>>>>> + * @saved_fmt: format used by the plane's FB, saved for for virtual plane support
>>>>>>>>> */
>>>>>>>>> struct dpu_plane_state {
>>>>>>>>> struct drm_plane_state base;
>>>>>>>>> @@ -46,6 +47,8 @@ struct dpu_plane_state {
>>>>>>>>> u64 plane_clk;
>>>>>>>>> bool needs_dirtyfb;
>>>>>>>>> +
>>>>>>>>> + const struct dpu_format *saved_fmt;
>>>>>>>>> };
>>>>>>>>
>>>>>>>> Why is saved_fmt needed?
>>>>>>>>
>>>>>>>> The use-case which comes to my mind is lets say if we have a RGB format and
>>>>>>>> we need to switch to a YUV format, basically switch from DMA to ViG SSPP,
>>>>>>>> then yes we have to mark planes_changed as we need to switch the underlying
>>>>>>>> SSPP that time, but why cant we simply check that by means of a check to see
>>>>>>>> if the fmt is YUV and whether CSC block is present in the SSPP.
>>>>>>>
>>>>>>> Yes, correct. And vice versa, going from YUV to RGB might free the VIG
>>>>>>> SSPP.
>>>>>>>
>>>>>>>>
>>>>>>>> This will lead to dpu_crtc_reassign_planes() getting called for format
>>>>>>>> changes even when the new format might be available in the same SSPP.
>>>>>>>
>>>>>>> So use 'needs_vig' instead of storing the format? Sounds good to me.
>>>>>>>
>>>>>>
>>>>>> Yes thats the idea. Basically "needs_reassignment". You could even go from
>>>>>> Vig to DMA if the use-case can just use DMA to save up Vig.
>>>>>>
>>>>>> Also, do we really need to cache anything in the plane state to track this?
>>>>>>
>>>>>> If we have a function called dpu_crtc_needs_plane_reassignment() will go
>>>>>> through the current plane state and the current SSPP from the global state
>>>>>> and see if needs reassignment.
>>>>>
>>>>> No, looking at the global state won't be possible here. I'd have to lock
>>>>> the private object before consulting it, which might cause EDEADLOCK
>>>>> later on during resource reallocation. So all necessary information
>>>>> should be stored in the dpu_plane_state.
>>>>>
>>>>
>>>> But you are already calling dpu_kms_get_global_state() in
>>>> dpu_crtc_reassign_planes().
>>>
>>> It happens at a different point. And I'm not sure how modeset locking
>>> will react to an attempt to lock the private object twice.
>>>
>>
>> hmm, I am missing the code flow a bit.
>>
>> Inside drm_atomic_helper_check_planes(), we first have plane's
>> atomic_check followed by crtc's.
>>
>> In plane's atomic_check is where we are setting planes_changed by
>> checking whether we need re-assignment of SSPPs.
>>
>> In CRTC's atomic_check is where we have the logic to check
>> planes_changed and reassign the SSPPs.
>>
>> We already call dpu_kms_get_global_state() in crtc atomic_check which
>> means we acquire the ctx for the private object.
>>
>> Would it be incorrect to acquire it in plane's atomic_check?
>>
>> If so, can we do one of below:
>>
>> 1) call drm_modeset_drop_locks() before plane's atomic_check ends. That
>> way within the drm_atomic_helper_check_planes(), only one ctx is tracked
>> at a time.
>
> No, if I understand it correctly, this would drop all lock, so all the
> objects are unlocked.
>
>>
>> 2) if (1) wont work, would dpu_kms_get_existing_global_state() help? For
>> that one we do not need the locking.
>
> I'll check whether this works as expected.
>
> But really I don't see a problem that you are trying to solve. It is
> too early to run SSPP allocation before dpu_crtc_atomic_check(). We
> need a set of all the plane states that are used by the CRTC. Even
> though it is not needed for this patch (it can work with just single
> plane state), it doesn't make sense to rewire that again, within the
> same patchset.
>
The problem I am trying to solve is to avoid caching any previous state
like saved_fmt OR needs_yuv in the state and keep growing that list when
that information is already available to us in the current global state.
I would like to avoid adding new cached information just to track prev
and current state unless that information is indeed not available.
>>
>>
>>>>
>>>>>>
>>>>>>>>
>>>>>>>>> #define to_dpu_plane_state(x) \
>>>>>>>>> @@ -75,6 +78,16 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
>>>>>>>>> uint32_t pipe, enum drm_plane_type type,
>>>>>>>>> unsigned long possible_crtcs);
>>>>>>>>> +/**
>>>>>>>>> + * dpu_plane_init_virtual - create new dpu virtualized plane
>>>>>>>>> + * @dev: Pointer to DRM device
>>>>>>>>> + * @type: Plane type - PRIMARY/OVERLAY/CURSOR
>>>>>>>>> + * @possible_crtcs: bitmask of crtc that can be attached to the given pipe
>>>>>>>>> + */
>>>>>>>>> +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
>>>>>>>>> + enum drm_plane_type type,
>>>>>>>>> + unsigned long possible_crtcs);
>>>>>>>>> +
>>>>>>>>> /**
>>>>>>>>> * dpu_plane_color_fill - enables color fill on plane
>>>>>>>>> * @plane: Pointer to DRM plane object
>>>>>>>>> @@ -91,4 +104,10 @@ void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable);
>>>>>>>>> static inline void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) {}
>>>>>>>>> #endif
>>>>>>>>> +int dpu_assign_plane_resources(struct dpu_global_state *global_state,
>>>>>>>>> + struct drm_atomic_state *state,
>>>>>>>>> + struct drm_crtc *crtc,
>>>>>>>>> + struct drm_plane_state **states,
>>>>>>>>> + unsigned int num_planes);
>>>>>>>>> +
>>>>>>>>> #endif /* _DPU_PLANE_H_ */
>>>>>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>>>>>>>> index 44938ba7a2b7..7264a4d44a14 100644
>>>>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>>>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>>>>>>>> @@ -694,6 +694,83 @@ int dpu_rm_reserve(
>>>>>>>>> return ret;
>>>>>>>>> }
>>>>>>>>> +struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
>>>>>>>>> + struct dpu_global_state *global_state,
>>>>>>>>> + struct drm_crtc *crtc,
>>>>>>>>> + struct dpu_rm_sspp_requirements *reqs)
>>>>>>>>> +{
>>>>>>>>> + uint32_t crtc_id = crtc->base.id;
>>>>>>>>> + unsigned int weight, best_weght = UINT_MAX;
>>>>>>>>
>>>>>>>> best_weight?
>>>>>>>
>>>>>>> Yes
>>>>>>>
>>>>>>>>
>>>>>>>>> + struct dpu_hw_sspp *hw_sspp;
>>>>>>>>> + unsigned long mask = 0;
>>>>>>>>> + int i, best_idx = -1;
>>>>>>>>> +
>>>>>>>>> + /*
>>>>>>>>> + * Don't take cursor feature into consideration until there is proper support for SSPP_CURSORn.
>>>>>>>>> + */
>>>>>>>>> + mask |= BIT(DPU_SSPP_CURSOR);
>>>>>>>>> +
>>>>>>>>> + if (reqs->scale)
>>>>>>>>> + mask |= BIT(DPU_SSPP_SCALER_RGB) |
>>>>>>>>> + BIT(DPU_SSPP_SCALER_QSEED2) |
>>>>>>>>> + BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE);
>>>>>>>>> +
>>>>>>>>> + if (reqs->yuv)
>>>>>>>>> + mask |= BIT(DPU_SSPP_CSC) |
>>>>>>>>> + BIT(DPU_SSPP_CSC_10BIT);
>>>>>>>>> +
>>>>>>>>> + if (reqs->rot90)
>>>>>>>>> + mask |= BIT(DPU_SSPP_INLINE_ROTATION);
>>>>>>>>> +
>>>>>>>>> + for (i = 0; i < ARRAY_SIZE(rm->hw_sspp); i++) {
>>>>>>>>> + if (!rm->hw_sspp[i])
>>>>>>>>> + continue;
>>>>>>>>> +
>>>>>>>>> + if (global_state->sspp_to_crtc_id[i])
>>>>>>>>> + continue;
>>>>>>>>> +
>>>>>>>>> + hw_sspp = rm->hw_sspp[i];
>>>>>>>>> +
>>>>>>>>> + /* skip incompatible planes */
>>>>>>>>> + if (reqs->scale && !hw_sspp->cap->sblk->scaler_blk.len)
>>>>>>>>> + continue;
>>>>>>>>> +
>>>>>>>>> + if (reqs->yuv && !hw_sspp->cap->sblk->csc_blk.len)
>>>>>>>>> + continue;
>>>>>>>>> +
>>>>>>>>> + if (reqs->rot90 && !(hw_sspp->cap->features & DPU_SSPP_INLINE_ROTATION))
>>>>>>>>> + continue;
>>>>>>>>> +
>>>>>>>>> + /*
>>>>>>>>> + * For non-yuv, non-scaled planes prefer simple (DMA or RGB)
>>>>>>>>> + * plane, falling back to VIG only if there are no such planes.
>>>>>>>>> + *
>>>>>>>>> + * This way we'd leave VIG sspps to be later used for YUV formats.
>>>>>>>>> + */
>>>>>>>>> + weight = hweight64(hw_sspp->cap->features & ~mask);
>>>>>>>>
>>>>>>>> This approach is assuming that ViG feature masks are more than DMA.
>>>>>>>> Hence the hweight of DMA SSPP's features is less than hweight of ViG SSPPs.
>>>>>>>>
>>>>>>>> Is this really true? Because there are other bits such as DMA_SDM845_MASK
>>>>>>>> which might increase the hweight of DMA SSPPs
>>>>>>>
>>>>>>> Which bits are present in the DMA mask, which are not present in the VIG
>>>>>>> mask? Also for the older platforms there are three kinds of planes: VIG,
>>>>>>> DMA and RGB. The selection algorithm should not require significant
>>>>>>> changes to support that case.
>>>>>>>
>>>>>>
>>>>>> DMA_SDM845_MASK has DPU_SSPP_QOS_8LVL which is not there in VIG_MSM8998_MASK
>>>>>> afaict. But we really cannot be counting the number of feature bits and
>>>>>> going by that.
>>>>>
>>>>> MSM8998 uses DMA_MSM8998_MASK, not DMA_SDM845_MASK.
>>>>>
>>
>> I forgot to update this point, for sm6375_sspp, it uses DMA_SDM845_MASK
>> for DMA and VIG_SDM845_MASK for VIG. So my point is applicable for
>> sm6375 atleast.
>
> DPU_SSPP_QOS_8LVL is enabled in both VIG_SDM845_MASK and DMA_SDM845_MASK
>
>>>>>> Hence, inherently, going by hweight is not right because whenever we add a
>>>>>> catalog change to add a new feature bit to SSPP, we have to come back here
>>>>>> and make sure this logic will not break.
>>>>>>>>
>>>>>>>> I would rather make it simpler.
>>>>>>>>
>>>>>>>> 1) if we need scaling || yuv, then we have to get only a Vig
>>>>>>>> 2) else, first try to get a DMA SSPP
>>>>>>>
>>>>>>> How would you distinguish between VIG and DMA?
>>>>>>>
>>>>>>
>>>>>> the type SSPP_TYPE_VIG OR SSPP_TYPE_DMA. We also have a SSPP_TYPE_RGB so
>>>>>> that should address your concern about the third type of plane (Vig, DMA,
>>>>>> RGB).
>>>>>
>>>>> I don't particularly like the idea of using type. We still need to
>>>>> evaluate plane's features. Consider QCM2290, where VIG planes do not
>>>>> support scaling.
>>>>>
>>>>> I will evaluate if I can rework this part to use type, while still
>>>>> checking for the feature bit. BTW: should we prefer RGB or DMA plane if
>>>>> all other conditions are met?
>>>>>
>>>>
>>>> Ok, qcm2290 really seems like an odd case but point taken.
>>>>
>>>> I am fine if it needs to be a combination of type and feature bit but
>>>> certainly not hweight of feature bit. If you want to use type along with
>>>> presence of scaler blk feature bit thats fine.
>>>>
>>>> I need to check if there is any feature loss in RGB Vs DMA. Let me check
>>>> and get back. This needs some history digging.
>>>
>>> Sure.
>
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 08/13] drm/msm/dpu: add support for virtual planes
2024-06-08 2:45 ` Abhinav Kumar
@ 2024-06-10 21:01 ` Abhinav Kumar
0 siblings, 0 replies; 50+ messages in thread
From: Abhinav Kumar @ 2024-06-10 21:01 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On 6/7/2024 7:45 PM, Abhinav Kumar wrote:
>
>
> On 6/7/2024 5:57 PM, Dmitry Baryshkov wrote:
>> On Sat, 8 Jun 2024 at 02:55, Abhinav Kumar <quic_abhinavk@quicinc.com>
>> wrote:
>>>
>>>
>>>
>>> On 6/7/2024 3:26 PM, Dmitry Baryshkov wrote:
>>>> On Sat, 8 Jun 2024 at 00:39, Abhinav Kumar
>>>> <quic_abhinavk@quicinc.com> wrote:
>>>>>
>>>>>
>>>>>
>>>>> On 6/7/2024 2:10 PM, Dmitry Baryshkov wrote:
>>>>>> On Fri, Jun 07, 2024 at 12:22:16PM -0700, Abhinav Kumar wrote:
>>>>>>>
>>>>>>>
>>>>>>> On 6/7/2024 12:16 AM, Dmitry Baryshkov wrote:
>>>>>>>> On Thu, Jun 06, 2024 at 03:21:11PM -0700, Abhinav Kumar wrote:
>>>>>>>>> On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
>>>>>>>>>> Only several SSPP blocks support such features as YUV output
>>>>>>>>>> or scaling,
>>>>>>>>>> thus different DRM planes have different features. Properly
>>>>>>>>>> utilizing
>>>>>>>>>> all planes requires the attention of the compositor, who should
>>>>>>>>>> prefer simpler planes to YUV-supporting ones. Otherwise it is
>>>>>>>>>> very easy
>>>>>>>>>> to end up in a situation when all featureful planes are already
>>>>>>>>>> allocated for simple windows, leaving no spare plane for YUV
>>>>>>>>>> playback.
>>>>>>>>>>
>>>>>>>>>> To solve this problem make all planes virtual. Each plane is
>>>>>>>>>> registered
>>>>>>>>>> as if it supports all possible features, but then at the
>>>>>>>>>> runtime during
>>>>>>>>>> the atomic_check phase the driver selects backing SSPP block
>>>>>>>>>> for each
>>>>>>>>>> plane.
>>>>>>>>>>
>>>>>>>>>> Note, this does not provide support for using two different
>>>>>>>>>> SSPP blocks
>>>>>>>>>> for a single plane or using two rectangles of an SSPP to drive
>>>>>>>>>> two
>>>>>>>>>> planes. Each plane still gets its own SSPP and can utilize
>>>>>>>>>> either a solo
>>>>>>>>>> rectangle or both multirect rectangles depending on the
>>>>>>>>>> resolution.
>>>>>>>>>>
>>>>>>>>>> Note #2: By default support for virtual planes is turned off
>>>>>>>>>> and the
>>>>>>>>>> driver still uses old code path with preallocated SSPP block
>>>>>>>>>> for each
>>>>>>>>>> plane. To enable virtual planes, pass
>>>>>>>>>> 'msm.dpu_use_virtual_planes=1'
>>>>>>>>>> kernel parameter.
>>>>>>>>>>
While posting the next revision, can you pls leave a note in the commit
text on the reason behind picking crtc_id for sspp allocation and not
encoder_id?
I recall you mentioned that, two rects of the smartDMA cannot goto two
LMs. This is true. But crtc mapping need not goto 1:1 with LM mapping.
It depends on topology. I think I forgot the full explanation for this
aspect of it. Hence it will be better to note that in the commit text.
>>>>>>>>>
>>>>>>>>> I like the overall approach in this patch. Some comments below.
>>>>>>>>>
>>>>>>>>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>>>>>>>>> ---
>>>>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 50 +++++
>>>>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 10 +-
>>>>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 4 +
>>>>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 230
>>>>>>>>>> +++++++++++++++++++---
>>>>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 19 ++
>>>>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 77 ++++++++
>>>>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 28 +++
>>>>>>>>>> 7 files changed, 390 insertions(+), 28 deletions(-)
>>>>>>>>>>
>>>>>>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>>>>>>> b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>>>>>>> index 88c2e51ab166..794c5643584f 100644
>>>>>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>>>>>>> @@ -1168,6 +1168,49 @@ static bool
>>>>>>>>>> dpu_crtc_needs_dirtyfb(struct drm_crtc_state *cstate)
>>>>>>>>>> return false;
>>>>>>>>>> }
>>>>>>>>>> +static int dpu_crtc_reassign_planes(struct drm_crtc *crtc,
>>>>>>>>>> struct drm_crtc_state *crtc_state)
>>>>>>>>>> +{
>>>>>>>>>> + int total_planes = crtc->dev->mode_config.num_total_plane;
>>>>>>>>>> + struct drm_atomic_state *state = crtc_state->state;
>>>>>>>>>> + struct dpu_global_state *global_state;
>>>>>>>>>> + struct drm_plane_state **states;
>>>>>>>>>> + struct drm_plane *plane;
>>>>>>>>>> + int ret;
>>>>>>>>>> +
>>>>>>>>>> + global_state = dpu_kms_get_global_state(crtc_state->state);
>>>>>>>>>> + if (IS_ERR(global_state))
>>>>>>>>>> + return PTR_ERR(global_state);
>>>>>>>>>> +
>>>>>>>>>> + dpu_rm_release_all_sspp(global_state, crtc);
>>>>>>>>>> +
>>>>>>>>>
>>>>>>>>> Do we need to call dpu_rm_release_all_sspp() even in the
>>>>>>>>> _dpu_plane_atomic_disable()?
>>>>>>>>
>>>>>>>> It allows the driver to optimize the usage of the SSPP rectangles.
>>>>>>>>
>>>>>>>
>>>>>>> No, what I meant was that we should call
>>>>>>> dpu_rm_release_all_sspp() in
>>>>>>> dpu_plane_atomic_update() as well because in the atomic_check()
>>>>>>> path where
>>>>>>> its called today, its being called only for zpos_changed and
>>>>>>> planes_changed
>>>>>>> but during disable we must call this for sure.
>>>>>>
>>>>>> No. the dpu_rm_release_all_sspp() should only be called during check.
>>>>>> When dpu_plane_atomic_update() is called, the state should already be
>>>>>> finalised. The atomic_check() callback is called when a plane is
>>>>>> going
>>>>>> to be disabled.
>>>>>>
>>>>>
>>>>> atomic_check() will be called when plane is disabled but
>>>>> dpu_rm_release_all_sspp() may not be called as it is protected by
>>>>> zpos_changed and planes_changed. OR you need to add a !visible check
>>>>> here to call dpu_rm_release_all_sspp() that time. Thats whay I wrote
>>>>> previously.
>>>>
>>>> Unless I miss something, if a plane gets disabled, then obviously
>>>> planes_changed is true.
>>>>
>>>> [trimmed]
>>>>
>>>
>>> Do you mean DRM fwk sets planes_changed correctly for this case?
>>>
>>> Currently we have
>>>
>>> if (!new_state->visible) {
>>> _dpu_plane_atomic_disable(plane);
>>> } else {
>>> dpu_plane_sspp_atomic_update(plane);
>>> }
>>>
>>> So I wanted to ensure that when plane gets disabled, its SSPP is freed
>>> too. If this is confirmed, I do not have any concerns.
>>
>> This is the atomic_update() path, not the atomic_check()
>>
>
> Yes, I am aware.
>
> Let me clarify my question here once again.
>
> 1) dpu_rm_release_all_sspp() gets called only in atomic_check() when
> either planes_changed or zpos_changed is set
> 2) But even in _dpu_plane_atomic_disable(), we should call
> dpu_rm_release_all_sspp() unconditionally. So for this, as you wrote,
> the corresponding atomic_check() call of _dpu_plane_atomic_disable() is
> supposed to do this. atomic_check() checks planes_changed and
> zpos_changed but not !visible before calling dpu_rm_release_all_sspp().
>
> Will planes_changed be set even when !visible?
>
> I am trying to make sure that dpu_rm_release_all_sspp() will get called
> for the _dpu_plane_atomic_disable(). Thats all.
>
>>>
>>>>>
>>>>>>>>>> @@ -1486,7 +1593,7 @@ struct drm_plane *dpu_plane_init(struct
>>>>>>>>>> drm_device *dev,
>>>>>>>>>> supported_rotations = DRM_MODE_REFLECT_MASK |
>>>>>>>>>> DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
>>>>>>>>>> - if (pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION))
>>>>>>>>>> + if (inline_rotation)
>>>>>>>>>> supported_rotations |= DRM_MODE_ROTATE_MASK;
>>>>>>>>>> drm_plane_create_rotation_property(plane,
>>>>>>>>>> @@ -1494,10 +1601,81 @@ struct drm_plane
>>>>>>>>>> *dpu_plane_init(struct drm_device *dev,
>>>>>>>>>> drm_plane_enable_fb_damage_clips(plane);
>>>>>>>>>> - /* success! finalize initialization */
>>>>>>>>>> + DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
>>>>>>>>>> + pipe, plane->base.id);
>>>>>>>>>> + return plane;
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> +struct drm_plane *dpu_plane_init(struct drm_device *dev,
>>>>>>>>>> + uint32_t pipe, enum drm_plane_type
>>>>>>>>>> type,
>>>>>>>>>> + unsigned long possible_crtcs)
>>>>>>>>>> +{
>>>>>>>>>> + struct drm_plane *plane = NULL;
>>>>>>>>>> + struct msm_drm_private *priv = dev->dev_private;
>>>>>>>>>> + struct dpu_kms *kms = to_dpu_kms(priv->kms);
>>>>>>>>>> + struct dpu_hw_sspp *pipe_hw;
>>>>>>>>>> +
>>>>>>>>>> + /* initialize underlying h/w driver */
>>>>>>>>>> + pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);
>>>>>>>>>> + if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {
>>>>>>>>>> + DPU_ERROR("[%u]SSPP is invalid\n", pipe);
>>>>>>>>>> + return ERR_PTR(-EINVAL);
>>>>>>>>>> + }
>>>>>>>>>> +
>>>>>>>>>> +
>>>>>>>>>> + plane = dpu_plane_init_common(dev, type, possible_crtcs,
>>>>>>>>>> + pipe_hw->cap->features &
>>>>>>>>>> BIT(DPU_SSPP_INLINE_ROTATION),
>>>>>>>>>> + pipe_hw->cap->sblk->format_list,
>>>>>>>>>> + pipe_hw->cap->sblk->num_formats,
>>>>>>>>>> + pipe);
>>>>>>>>>> + if (IS_ERR(plane))
>>>>>>>>>> + return plane;
>>>>>>>>>> +
>>>>>>>>>> drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
>>>>>>>>>> DPU_DEBUG("%s created for pipe:%u id:%u\n",
>>>>>>>>>> plane->name,
>>>>>>>>>> pipe,
>>>>>>>>>> plane->base.id);
>>>>>>>>>> +
>>>>>>>>>> + return plane;
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
>>>>>>>>>> + enum drm_plane_type type,
>>>>>>>>>> + unsigned long possible_crtcs)
>>>>>>>>>> +{
>>>>>>>>>> + struct drm_plane *plane = NULL;
>>>>>>>>>> + struct msm_drm_private *priv = dev->dev_private;
>>>>>>>>>> + struct dpu_kms *kms = to_dpu_kms(priv->kms);
>>>>>>>>>> + bool has_inline_rotation = false;
>>>>>>>>>> + const u32 *format_list = NULL;
>>>>>>>>>> + u32 num_formats = 0;
>>>>>>>>>> + int i;
>>>>>>>>>> +
>>>>>>>>>> + /* Determine the largest configuration that we can implement */
>>>>>>>>>> + for (i = 0; i < kms->catalog->sspp_count; i++) {
>>>>>>>>>> + const struct dpu_sspp_cfg *cfg =
>>>>>>>>>> &kms->catalog->sspp[i];
>>>>>>>>>> +
>>>>>>>>>> + if (test_bit(DPU_SSPP_INLINE_ROTATION, &cfg->features))
>>>>>>>>>> + has_inline_rotation = true;
>>>>>>>>>> +
>>>>>>>>>> + if (!format_list ||
>>>>>>>>>> + cfg->sblk->csc_blk.len) {
>>>>>>>>>
>>>>>>>>> But format_list is being assigned to NULL just a few lines
>>>>>>>>> above. Why is
>>>>>>>>> this check needed?
>>>>>>>>
>>>>>>>> It was assigned before the loop.
>>>>>>>>
>>>>>>>
>>>>>>> Yes, I got this part but missed on why we needed the loop at all.
>>>>>>
>>>>>> Which set of formats should the virtual plane use?
>>>>>>
>>>>>>>>>
>>>>>>>>> I dont get why this part can also goto dpu_plane_init_common()
>>>>>>>>> as it looks
>>>>>>>>> identical to me.
>>>>>>>>
>>>>>>>> And it is not. For the non-virtual case there is no loop around
>>>>>>>> formats
>>>>>>>> list assignment.
>>>>>>>>
>>>>>>>
>>>>>>> Ah okay, I misunderstood the logic. After reading the comment
>>>>>>> above the loop
>>>>>>> I get what you are trying to do here.
>>>>>>>
>>>>>>> But I dont get why you really need to do that?
>>>>>>>
>>>>>>> 1) In this patch the relationship between virtual plane and SSPP
>>>>>>> is still
>>>>>>> 1:1 so what is wrong to retain the sspp's actual format for the
>>>>>>> plane rather
>>>>>>> than picking the best format (you are targetting Vig SSPP)
>>>>>>
>>>>>> No. With this patch there is no 1:1 relationship. The RM will
>>>>>> select the
>>>>>> SSPP that suits the requirements (YUV, scaling, rotation, etc).
>>>>>>
>>>>>
>>>>> Yes but there is always only one SSPP for one plane is what I meant.
>>>>> That does not change till the next patch.
>>>>>
>>>>> In that sense, I dont see why you need to expose the superset of
>>>>> formats.
>>>>
>>>> Let me please repeat my question: what set of formats should be used
>>>> for plane init?
>>>>
>>>
>>> So, my point here was that in the loop, in this patch, we create one
>>> plane for one SSPP, why dont we just use the same SSPP's format for that
>>> plane.
>>
>> Which SSPP? There is no SSPP attached to a virtual plane.
>>
>
> dpu_plane_init_virtual() gets called for each SSPP of the catalog in
> this patchset just like dpu_plane_init().
>
> The only difference is dpu_plane_init() also passes the pipe but
> dpu_plane_init_virtual() does not.
>
> Would it be incorrect to also pass along the sspp's fmt list (from the
> catalog->sspp loop) to dpu_plane_init_virtual() instead of the superset?
>
>>>
>>> In the next patch, when the same plane can attach to two different
>>> SSPPs, we will use the superset of the SSPPs. IOW, do we need the
>>> superset in this patch itself?
>>>
>>>>>
>>>>>>> In fact, that will reduce atomic_check() failures with this patch
>>>>>>> because
>>>>>>> compositor will still work the same way as it used to work before
>>>>>>> by not
>>>>>>> trying an unsupported format on a plane.
>>>>>>
>>>>>> The virtual plane should support any of the formats that the backing
>>>>>> hardware can support. If (for example) we only had RGB-only and
>>>>>> YUV-only
>>>>>> hardware blocks, the driver would have to construct a _superset_ of
>>>>>> those formats. Fortunately this is not the case and VIG supports a
>>>>>> strict superset of what DMA (or RGB) SSPP supports.
>>>>>>
>>>>>
>>>>> Yes, thats why I said plane_formats_yuv is enough in my next point
>>>>> below
>>>>> because Vig is super set of DMA or IOW Vig is the most feature rich
>>>>> plane.
>>>>
>>>> QCM2290 doesn't have YUV support if I'm not mistaken.
>>>>
>>>
>>> qcm2290_sspp has YUV support but no scaling support as per the catalog.
>>> It uses _VIG_SBLK_NOSCALE which still has plane_formats_yuv.
>>
>> I'll check it on the real hw. I remember that I had questions
>> regarding it.
>>
>>>
>>>>>
>>>>>>> If one plane maps to two SSPPs, then yes we can go with the
>>>>>>> superset of
>>>>>>> formats but that comes in a later patch right?
>>>>>>>
>>>>>>> 2) So even if we want to do it this way from this patch itself, I
>>>>>>> think all
>>>>>>> you are looking for is whether there is a Vig SSPP and if so use
>>>>>>> plane_formats_yuv. There is no need for this loop IMO.
>>>>>>>
>>>>>>> 3) I noticed that virt_format_list is still present in the
>>>>>>> driver. If you
>>>>>>> are planning to not use that perhaps drop it with this series.
>>>>>>
>>>>>> Ack
>>>>>>
>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>> + format_list = cfg->sblk->format_list;
>>>>>>>>>> + num_formats = cfg->sblk->num_formats;
>>>>>>>>>> + }
>>>>>>>>>> + }
>>>>>>>>>> +
>>>>>>>>>> + plane = dpu_plane_init_common(dev, type, possible_crtcs,
>>>>>>>>>> + has_inline_rotation,
>>>>>>>>>> + format_list,
>>>>>>>>>> + num_formats,
>>>>>>>>>> + SSPP_NONE);
>>>>>>>>>
>>>>>>>>> Ok, here is the part which we were discussing in
>>>>>>>>>
>>>>>>>>> https://patchwork.freedesktop.org/patch/582820/?series=131109&rev=1#comment_1087370
>>>>>>>>>
>>>>>>>>> So yes, that part belongs to this patch.
>>>>>>>>
>>>>>>>> I'll check it while preparing the next iteration.
>>>>>>>>
>>>>>>>>>
>>>>>>>>>> + if (IS_ERR(plane))
>>>>>>>>>> + return plane;
>>>>>>>>>> +
>>>>>>>>>> + drm_plane_helper_add(plane, &dpu_plane_virtual_helper_funcs);
>>>>>>>>>> +
>>>>>>>>>> + DPU_DEBUG("%s created virtual id:%u\n", plane->name,
>>>>>>>>>> plane->base.id);
>>>>>>>>>> +
>>>>>>>>>> return plane;
>>>>>>>>>> }
>>>>>>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>>>>>>>>>> b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>>>>>>>>>> index a3ae45dc95d0..15f7d60d8b85 100644
>>>>>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>>>>>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>>>>>>>>>> @@ -30,6 +30,7 @@
>>>>>>>>>> * @plane_fetch_bw: calculated BW per plane
>>>>>>>>>> * @plane_clk: calculated clk per plane
>>>>>>>>>> * @needs_dirtyfb: whether attached CRTC needs pixel
>>>>>>>>>> data explicitly flushed
>>>>>>>>>> + * @saved_fmt: format used by the plane's FB, saved for for
>>>>>>>>>> virtual plane support
>>>>>>>>>> */
>>>>>>>>>> struct dpu_plane_state {
>>>>>>>>>> struct drm_plane_state base;
>>>>>>>>>> @@ -46,6 +47,8 @@ struct dpu_plane_state {
>>>>>>>>>> u64 plane_clk;
>>>>>>>>>> bool needs_dirtyfb;
>>>>>>>>>> +
>>>>>>>>>> + const struct dpu_format *saved_fmt;
>>>>>>>>>> };
>>>>>>>>>
>>>>>>>>> Why is saved_fmt needed?
>>>>>>>>>
>>>>>>>>> The use-case which comes to my mind is lets say if we have a
>>>>>>>>> RGB format and
>>>>>>>>> we need to switch to a YUV format, basically switch from DMA to
>>>>>>>>> ViG SSPP,
>>>>>>>>> then yes we have to mark planes_changed as we need to switch
>>>>>>>>> the underlying
>>>>>>>>> SSPP that time, but why cant we simply check that by means of a
>>>>>>>>> check to see
>>>>>>>>> if the fmt is YUV and whether CSC block is present in the SSPP.
>>>>>>>>
>>>>>>>> Yes, correct. And vice versa, going from YUV to RGB might free
>>>>>>>> the VIG
>>>>>>>> SSPP.
>>>>>>>>
>>>>>>>>>
>>>>>>>>> This will lead to dpu_crtc_reassign_planes() getting called for
>>>>>>>>> format
>>>>>>>>> changes even when the new format might be available in the same
>>>>>>>>> SSPP.
>>>>>>>>
>>>>>>>> So use 'needs_vig' instead of storing the format? Sounds good to
>>>>>>>> me.
>>>>>>>>
>>>>>>>
>>>>>>> Yes thats the idea. Basically "needs_reassignment". You could
>>>>>>> even go from
>>>>>>> Vig to DMA if the use-case can just use DMA to save up Vig.
>>>>>>>
>>>>>>> Also, do we really need to cache anything in the plane state to
>>>>>>> track this?
>>>>>>>
>>>>>>> If we have a function called dpu_crtc_needs_plane_reassignment()
>>>>>>> will go
>>>>>>> through the current plane state and the current SSPP from the
>>>>>>> global state
>>>>>>> and see if needs reassignment.
>>>>>>
>>>>>> No, looking at the global state won't be possible here. I'd have
>>>>>> to lock
>>>>>> the private object before consulting it, which might cause EDEADLOCK
>>>>>> later on during resource reallocation. So all necessary information
>>>>>> should be stored in the dpu_plane_state.
>>>>>>
>>>>>
>>>>> But you are already calling dpu_kms_get_global_state() in
>>>>> dpu_crtc_reassign_planes().
>>>>
>>>> It happens at a different point. And I'm not sure how modeset locking
>>>> will react to an attempt to lock the private object twice.
>>>>
>>>
>>> hmm, I am missing the code flow a bit.
>>>
>>> Inside drm_atomic_helper_check_planes(), we first have plane's
>>> atomic_check followed by crtc's.
>>>
>>> In plane's atomic_check is where we are setting planes_changed by
>>> checking whether we need re-assignment of SSPPs.
>>>
>>> In CRTC's atomic_check is where we have the logic to check
>>> planes_changed and reassign the SSPPs.
>>>
>>> We already call dpu_kms_get_global_state() in crtc atomic_check which
>>> means we acquire the ctx for the private object.
>>>
>>> Would it be incorrect to acquire it in plane's atomic_check?
>>>
>>> If so, can we do one of below:
>>>
>>> 1) call drm_modeset_drop_locks() before plane's atomic_check ends. That
>>> way within the drm_atomic_helper_check_planes(), only one ctx is tracked
>>> at a time.
>>
>> No, if I understand it correctly, this would drop all lock, so all the
>> objects are unlocked.
>>
>>>
>>> 2) if (1) wont work, would dpu_kms_get_existing_global_state() help? For
>>> that one we do not need the locking.
>>
>> I'll check whether this works as expected.
>>
>> But really I don't see a problem that you are trying to solve. It is
>> too early to run SSPP allocation before dpu_crtc_atomic_check(). We
>> need a set of all the plane states that are used by the CRTC. Even
>> though it is not needed for this patch (it can work with just single
>> plane state), it doesn't make sense to rewire that again, within the
>> same patchset.
>>
>
> The problem I am trying to solve is to avoid caching any previous state
> like saved_fmt OR needs_yuv in the state and keep growing that list when
> that information is already available to us in the current global state.
>
> I would like to avoid adding new cached information just to track prev
> and current state unless that information is indeed not available.
>
>>>
>>>
>>>>>
>>>>>>>
>>>>>>>>>
>>>>>>>>>> #define to_dpu_plane_state(x) \
>>>>>>>>>> @@ -75,6 +78,16 @@ struct drm_plane *dpu_plane_init(struct
>>>>>>>>>> drm_device *dev,
>>>>>>>>>> uint32_t pipe, enum drm_plane_type type,
>>>>>>>>>> unsigned long possible_crtcs);
>>>>>>>>>> +/**
>>>>>>>>>> + * dpu_plane_init_virtual - create new dpu virtualized plane
>>>>>>>>>> + * @dev: Pointer to DRM device
>>>>>>>>>> + * @type: Plane type - PRIMARY/OVERLAY/CURSOR
>>>>>>>>>> + * @possible_crtcs: bitmask of crtc that can be attached to
>>>>>>>>>> the given pipe
>>>>>>>>>> + */
>>>>>>>>>> +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
>>>>>>>>>> + enum drm_plane_type type,
>>>>>>>>>> + unsigned long possible_crtcs);
>>>>>>>>>> +
>>>>>>>>>> /**
>>>>>>>>>> * dpu_plane_color_fill - enables color fill on plane
>>>>>>>>>> * @plane: Pointer to DRM plane object
>>>>>>>>>> @@ -91,4 +104,10 @@ void dpu_plane_danger_signal_ctrl(struct
>>>>>>>>>> drm_plane *plane, bool enable);
>>>>>>>>>> static inline void dpu_plane_danger_signal_ctrl(struct
>>>>>>>>>> drm_plane *plane, bool enable) {}
>>>>>>>>>> #endif
>>>>>>>>>> +int dpu_assign_plane_resources(struct dpu_global_state
>>>>>>>>>> *global_state,
>>>>>>>>>> + struct drm_atomic_state *state,
>>>>>>>>>> + struct drm_crtc *crtc,
>>>>>>>>>> + struct drm_plane_state **states,
>>>>>>>>>> + unsigned int num_planes);
>>>>>>>>>> +
>>>>>>>>>> #endif /* _DPU_PLANE_H_ */
>>>>>>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>>>>>>>>> b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>>>>>>>>> index 44938ba7a2b7..7264a4d44a14 100644
>>>>>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>>>>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>>>>>>>>> @@ -694,6 +694,83 @@ int dpu_rm_reserve(
>>>>>>>>>> return ret;
>>>>>>>>>> }
>>>>>>>>>> +struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
>>>>>>>>>> + struct dpu_global_state
>>>>>>>>>> *global_state,
>>>>>>>>>> + struct drm_crtc *crtc,
>>>>>>>>>> + struct
>>>>>>>>>> dpu_rm_sspp_requirements *reqs)
>>>>>>>>>> +{
>>>>>>>>>> + uint32_t crtc_id = crtc->base.id;
>>>>>>>>>> + unsigned int weight, best_weght = UINT_MAX;
>>>>>>>>>
>>>>>>>>> best_weight?
>>>>>>>>
>>>>>>>> Yes
>>>>>>>>
>>>>>>>>>
>>>>>>>>>> + struct dpu_hw_sspp *hw_sspp;
>>>>>>>>>> + unsigned long mask = 0;
>>>>>>>>>> + int i, best_idx = -1;
>>>>>>>>>> +
>>>>>>>>>> + /*
>>>>>>>>>> + * Don't take cursor feature into consideration until there
>>>>>>>>>> is proper support for SSPP_CURSORn.
>>>>>>>>>> + */
>>>>>>>>>> + mask |= BIT(DPU_SSPP_CURSOR);
>>>>>>>>>> +
>>>>>>>>>> + if (reqs->scale)
>>>>>>>>>> + mask |= BIT(DPU_SSPP_SCALER_RGB) |
>>>>>>>>>> + BIT(DPU_SSPP_SCALER_QSEED2) |
>>>>>>>>>> + BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE);
>>>>>>>>>> +
>>>>>>>>>> + if (reqs->yuv)
>>>>>>>>>> + mask |= BIT(DPU_SSPP_CSC) |
>>>>>>>>>> + BIT(DPU_SSPP_CSC_10BIT);
>>>>>>>>>> +
>>>>>>>>>> + if (reqs->rot90)
>>>>>>>>>> + mask |= BIT(DPU_SSPP_INLINE_ROTATION);
>>>>>>>>>> +
>>>>>>>>>> + for (i = 0; i < ARRAY_SIZE(rm->hw_sspp); i++) {
>>>>>>>>>> + if (!rm->hw_sspp[i])
>>>>>>>>>> + continue;
>>>>>>>>>> +
>>>>>>>>>> + if (global_state->sspp_to_crtc_id[i])
>>>>>>>>>> + continue;
>>>>>>>>>> +
>>>>>>>>>> + hw_sspp = rm->hw_sspp[i];
>>>>>>>>>> +
>>>>>>>>>> + /* skip incompatible planes */
>>>>>>>>>> + if (reqs->scale && !hw_sspp->cap->sblk->scaler_blk.len)
>>>>>>>>>> + continue;
>>>>>>>>>> +
>>>>>>>>>> + if (reqs->yuv && !hw_sspp->cap->sblk->csc_blk.len)
>>>>>>>>>> + continue;
>>>>>>>>>> +
>>>>>>>>>> + if (reqs->rot90 && !(hw_sspp->cap->features &
>>>>>>>>>> DPU_SSPP_INLINE_ROTATION))
>>>>>>>>>> + continue;
>>>>>>>>>> +
>>>>>>>>>> + /*
>>>>>>>>>> + * For non-yuv, non-scaled planes prefer simple (DMA
>>>>>>>>>> or RGB)
>>>>>>>>>> + * plane, falling back to VIG only if there are no
>>>>>>>>>> such planes.
>>>>>>>>>> + *
>>>>>>>>>> + * This way we'd leave VIG sspps to be later used
>>>>>>>>>> for YUV formats.
>>>>>>>>>> + */
>>>>>>>>>> + weight = hweight64(hw_sspp->cap->features & ~mask);
>>>>>>>>>
>>>>>>>>> This approach is assuming that ViG feature masks are more than
>>>>>>>>> DMA.
>>>>>>>>> Hence the hweight of DMA SSPP's features is less than hweight
>>>>>>>>> of ViG SSPPs.
>>>>>>>>>
>>>>>>>>> Is this really true? Because there are other bits such as
>>>>>>>>> DMA_SDM845_MASK
>>>>>>>>> which might increase the hweight of DMA SSPPs
>>>>>>>>
>>>>>>>> Which bits are present in the DMA mask, which are not present in
>>>>>>>> the VIG
>>>>>>>> mask? Also for the older platforms there are three kinds of
>>>>>>>> planes: VIG,
>>>>>>>> DMA and RGB. The selection algorithm should not require significant
>>>>>>>> changes to support that case.
>>>>>>>>
>>>>>>>
>>>>>>> DMA_SDM845_MASK has DPU_SSPP_QOS_8LVL which is not there in
>>>>>>> VIG_MSM8998_MASK
>>>>>>> afaict. But we really cannot be counting the number of feature
>>>>>>> bits and
>>>>>>> going by that.
>>>>>>
>>>>>> MSM8998 uses DMA_MSM8998_MASK, not DMA_SDM845_MASK.
>>>>>>
>>>
>>> I forgot to update this point, for sm6375_sspp, it uses DMA_SDM845_MASK
>>> for DMA and VIG_SDM845_MASK for VIG. So my point is applicable for
>>> sm6375 atleast.
>>
>> DPU_SSPP_QOS_8LVL is enabled in both VIG_SDM845_MASK and DMA_SDM845_MASK
>>
>>>>>>> Hence, inherently, going by hweight is not right because whenever
>>>>>>> we add a
>>>>>>> catalog change to add a new feature bit to SSPP, we have to come
>>>>>>> back here
>>>>>>> and make sure this logic will not break.
>>>>>>>>>
>>>>>>>>> I would rather make it simpler.
>>>>>>>>>
>>>>>>>>> 1) if we need scaling || yuv, then we have to get only a Vig
>>>>>>>>> 2) else, first try to get a DMA SSPP
>>>>>>>>
>>>>>>>> How would you distinguish between VIG and DMA?
>>>>>>>>
>>>>>>>
>>>>>>> the type SSPP_TYPE_VIG OR SSPP_TYPE_DMA. We also have a
>>>>>>> SSPP_TYPE_RGB so
>>>>>>> that should address your concern about the third type of plane
>>>>>>> (Vig, DMA,
>>>>>>> RGB).
>>>>>>
>>>>>> I don't particularly like the idea of using type. We still need to
>>>>>> evaluate plane's features. Consider QCM2290, where VIG planes do not
>>>>>> support scaling.
>>>>>>
>>>>>> I will evaluate if I can rework this part to use type, while still
>>>>>> checking for the feature bit. BTW: should we prefer RGB or DMA
>>>>>> plane if
>>>>>> all other conditions are met?
>>>>>>
>>>>>
>>>>> Ok, qcm2290 really seems like an odd case but point taken.
>>>>>
>>>>> I am fine if it needs to be a combination of type and feature bit but
>>>>> certainly not hweight of feature bit. If you want to use type along
>>>>> with
>>>>> presence of scaler blk feature bit thats fine.
>>>>>
>>>>> I need to check if there is any feature loss in RGB Vs DMA. Let me
>>>>> check
>>>>> and get back. This needs some history digging.
>>>>
>>>> Sure.
>>
^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v4 09/13] drm/msm/dpu: allow using two SSPP blocks for a single plane
2024-03-14 0:02 [PATCH v4 00/13] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
` (7 preceding siblings ...)
2024-03-14 0:02 ` [PATCH v4 08/13] drm/msm/dpu: add support for virtual planes Dmitry Baryshkov
@ 2024-03-14 0:02 ` Dmitry Baryshkov
2024-06-10 20:19 ` Abhinav Kumar
2024-03-14 0:02 ` [PATCH v4 10/13] drm/msm/dpu: allow sharing SSPP between planes Dmitry Baryshkov
` (4 subsequent siblings)
13 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-03-14 0:02 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Abhinav Kumar, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
Virtual wide planes give high amount of flexibility, but it is not
always enough:
In parallel multirect case only the half of the usual width is supported
for tiled formats. Thus the whole width of two tiled multirect
rectangles can not be greater than max_linewidth, which is not enough
for some platforms/compositors.
Another example is as simple as wide YUV plane. YUV planes can not use
multirect, so currently they are limited to max_linewidth too.
Now that the planes are fully virtualized, add support for allocating
two SSPP blocks to drive a single DRM plane. This fixes both mentioned
cases and allows all planes to go up to 2*max_linewidth (at the cost of
making some of the planes unavailable to the user).
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 172 ++++++++++++++++------
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 8 +
2 files changed, 131 insertions(+), 49 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index 2961b809ccf3..cde20c1fa90d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -886,6 +886,28 @@ static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
return 0;
}
+static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
+ struct dpu_sw_pipe_cfg *pipe_cfg,
+ const struct dpu_format *fmt,
+ uint32_t max_linewidth)
+{
+ 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))
+ return false;
+
+ if (pipe_cfg->rotation & DRM_MODE_ROTATE_90)
+ return false;
+
+ if (DPU_FORMAT_IS_YUV(fmt))
+ return false;
+
+ if (DPU_FORMAT_IS_UBWC(fmt) &&
+ drm_rect_width(&pipe_cfg->src_rect) > max_linewidth / 2)
+ return false;
+
+ return true;
+}
+
static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
struct drm_atomic_state *state,
const struct drm_crtc_state *crtc_state)
@@ -899,7 +921,6 @@ static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
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;
- uint32_t max_linewidth;
uint32_t supported_rotations;
const struct dpu_sspp_cfg *pipe_hw_caps;
const struct dpu_sspp_sub_blks *sblk;
@@ -919,15 +940,8 @@ static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
drm_rect_height(&new_plane_state->dst))))
return -ERANGE;
- 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;
-
fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
- max_linewidth = pdpu->catalog->caps->max_linewidth;
-
supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0;
if (pipe_hw_caps->features & BIT(DPU_SSPP_INLINE_ROTATION))
@@ -943,41 +957,6 @@ static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
return ret;
if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) {
- /*
- * In parallel multirect case only the half of the usual width
- * is supported for tiled formats. If we are here, we know that
- * full width is more than max_linewidth, thus each rect is
- * wider than allowed.
- */
- if (DPU_FORMAT_IS_UBWC(fmt) &&
- drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) {
- DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u, tiled format\n",
- DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);
- return -E2BIG;
- }
-
- 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)) ||
- pipe_cfg->rotation & DRM_MODE_ROTATE_90 ||
- 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;
- }
-
- /*
- * 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;
-
ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, fmt,
&crtc_state->adjusted_mode);
if (ret)
@@ -998,16 +977,16 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
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;
const struct drm_crtc_state *crtc_state = NULL;
if (new_plane_state->crtc)
crtc_state = drm_atomic_get_new_crtc_state(state,
new_plane_state->crtc);
- if (pdpu->pipe != SSPP_NONE) {
- pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
- r_pipe->sspp = NULL;
- }
+ pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
+ r_pipe->sspp = NULL;
if (!pipe->sspp)
return -EINVAL;
@@ -1019,6 +998,52 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
if (!new_plane_state->visible)
return 0;
+ 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;
+
+ if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) {
+ uint32_t max_linewidth = dpu_kms->catalog->caps->max_linewidth;
+ const struct dpu_format *fmt;
+
+ fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
+
+ /*
+ * In parallel multirect case only the half of the usual width
+ * is supported for tiled formats. If we are here, we know that
+ * full width is more than max_linewidth, thus each rect is
+ * wider than allowed.
+ */
+ if (DPU_FORMAT_IS_UBWC(fmt) &&
+ drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) {
+ DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u, tiled format\n",
+ DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);
+ return -E2BIG;
+ }
+
+ r_pipe->sspp = pipe->sspp;
+
+ if (!dpu_plane_is_multirect_parallel_capable(pipe, pipe_cfg, fmt, max_linewidth) ||
+ !dpu_plane_is_multirect_parallel_capable(r_pipe, r_pipe_cfg, fmt, max_linewidth) ||
+ !(test_bit(DPU_SSPP_SMART_DMA_V1, &pipe->sspp->cap->features) ||
+ test_bit(DPU_SSPP_SMART_DMA_V2, &pipe->sspp->cap->features))) {
+ 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;
+ }
+
+ /*
+ * 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->multirect_index = DPU_SSPP_RECT_1;
+ r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
+ }
+
return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
}
@@ -1053,10 +1078,18 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
format = to_dpu_format(msm_framebuffer_format(plane_state->fb));
- /* force resource reallocation if the format of FB has changed */
- if (pstate->saved_fmt != format) {
+ /* force resource reallocation if the format of FB or src/dst have changed */
+ if (pstate->saved_fmt != format ||
+ pstate->saved_src_w != plane_state->src_w ||
+ pstate->saved_src_h != plane_state->src_h ||
+ pstate->saved_src_w != plane_state->src_w ||
+ pstate->saved_crtc_h != plane_state->crtc_h) {
crtc_state->planes_changed = true;
pstate->saved_fmt = format;
+ pstate->saved_src_w = plane_state->src_w;
+ pstate->saved_src_h = plane_state->src_h;
+ pstate->saved_crtc_w = plane_state->crtc_w;
+ pstate->saved_crtc_h = plane_state->crtc_h;
}
return 0;
@@ -1074,7 +1107,10 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
struct dpu_plane_state *pstate;
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 dpu_format *fmt;
+ uint32_t max_linewidth;
if (plane_state->crtc)
crtc_state = drm_atomic_get_new_crtc_state(state,
@@ -1083,6 +1119,8 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
pstate = to_dpu_plane_state(plane_state);
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;
@@ -1097,10 +1135,46 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
reqs.rot90 = drm_rotation_90_or_270(plane_state->rotation);
+ max_linewidth = dpu_kms->catalog->caps->max_linewidth;
+
pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
if (!pipe->sspp)
return -ENODEV;
+ if (drm_rect_width(&r_pipe_cfg->src_rect) == 0) {
+ 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;
+ } else {
+ if (dpu_plane_is_multirect_parallel_capable(pipe, pipe_cfg, fmt, max_linewidth) &&
+ dpu_plane_is_multirect_parallel_capable(r_pipe, r_pipe_cfg, fmt, max_linewidth) &&
+ (test_bit(DPU_SSPP_SMART_DMA_V1, &pipe->sspp->cap->features) ||
+ test_bit(DPU_SSPP_SMART_DMA_V2, &pipe->sspp->cap->features))) {
+ r_pipe->sspp = pipe->sspp;
+
+ pipe->multirect_index = DPU_SSPP_RECT_0;
+ pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
+
+ r_pipe->multirect_index = DPU_SSPP_RECT_1;
+ r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
+ } else {
+ /* 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;
+ }
+ }
+
return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
index 15f7d60d8b85..5522f9035d68 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
@@ -31,6 +31,10 @@
* @plane_clk: calculated clk per plane
* @needs_dirtyfb: whether attached CRTC needs pixel data explicitly flushed
* @saved_fmt: format used by the plane's FB, saved for for virtual plane support
+ * @saved_src_w: cached value of plane's src_w, saved for for virtual plane support
+ * @saved_src_h: cached value of plane's src_h, saved for for virtual plane support
+ * @saved_crtc_w: cached value of plane's crtc_w, saved for for virtual plane support
+ * @saved_crtc_h: cached value of plane's crtc_h, saved for for virtual plane support
*/
struct dpu_plane_state {
struct drm_plane_state base;
@@ -49,6 +53,10 @@ struct dpu_plane_state {
bool needs_dirtyfb;
const struct dpu_format *saved_fmt;
+ uint32_t saved_src_w;
+ uint32_t saved_src_h;
+ uint32_t saved_crtc_w;
+ uint32_t saved_crtc_h;
};
#define to_dpu_plane_state(x) \
--
2.39.2
^ permalink raw reply related [flat|nested] 50+ messages in thread* Re: [PATCH v4 09/13] drm/msm/dpu: allow using two SSPP blocks for a single plane
2024-03-14 0:02 ` [PATCH v4 09/13] drm/msm/dpu: allow using two SSPP blocks for a single plane Dmitry Baryshkov
@ 2024-06-10 20:19 ` Abhinav Kumar
0 siblings, 0 replies; 50+ messages in thread
From: Abhinav Kumar @ 2024-06-10 20:19 UTC (permalink / raw)
To: Dmitry Baryshkov, Rob Clark, Sean Paul, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> Virtual wide planes give high amount of flexibility, but it is not
> always enough:
>
> In parallel multirect case only the half of the usual width is supported
> for tiled formats. Thus the whole width of two tiled multirect
> rectangles can not be greater than max_linewidth, which is not enough
> for some platforms/compositors.
>
> Another example is as simple as wide YUV plane. YUV planes can not use
> multirect, so currently they are limited to max_linewidth too.
>
> Now that the planes are fully virtualized, add support for allocating
> two SSPP blocks to drive a single DRM plane. This fixes both mentioned
> cases and allows all planes to go up to 2*max_linewidth (at the cost of
> making some of the planes unavailable to the user).
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 172 ++++++++++++++++------
> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 8 +
> 2 files changed, 131 insertions(+), 49 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> index 2961b809ccf3..cde20c1fa90d 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> @@ -886,6 +886,28 @@ static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
> return 0;
> }
>
> +static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
> + struct dpu_sw_pipe_cfg *pipe_cfg,
> + const struct dpu_format *fmt,
> + uint32_t max_linewidth)
> +{
> + 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))
> + return false;
> +
> + if (pipe_cfg->rotation & DRM_MODE_ROTATE_90)
> + return false;
> +
> + if (DPU_FORMAT_IS_YUV(fmt))
> + return false;
> +
> + if (DPU_FORMAT_IS_UBWC(fmt) &&
> + drm_rect_width(&pipe_cfg->src_rect) > max_linewidth / 2)
> + return false;
> +
> + return true;
> +}
> +
This is a good idea to separate out multirect checks to a separate API.
I think can push this part of the change even today.
> static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
> struct drm_atomic_state *state,
> const struct drm_crtc_state *crtc_state)
> @@ -899,7 +921,6 @@ static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
> 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;
> - uint32_t max_linewidth;
> uint32_t supported_rotations;
> const struct dpu_sspp_cfg *pipe_hw_caps;
> const struct dpu_sspp_sub_blks *sblk;
> @@ -919,15 +940,8 @@ static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
> drm_rect_height(&new_plane_state->dst))))
> return -ERANGE;
>
> - 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;
> -
> fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
>
> - max_linewidth = pdpu->catalog->caps->max_linewidth;
> -
> supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0;
>
> if (pipe_hw_caps->features & BIT(DPU_SSPP_INLINE_ROTATION))
> @@ -943,41 +957,6 @@ static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
> return ret;
>
> if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) {
> - /*
> - * In parallel multirect case only the half of the usual width
> - * is supported for tiled formats. If we are here, we know that
> - * full width is more than max_linewidth, thus each rect is
> - * wider than allowed.
> - */
> - if (DPU_FORMAT_IS_UBWC(fmt) &&
> - drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) {
> - DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u, tiled format\n",
> - DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);
> - return -E2BIG;
> - }
> -
> - 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)) ||
> - pipe_cfg->rotation & DRM_MODE_ROTATE_90 ||
> - 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;
> - }
> -
> - /*
> - * 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;
> -
> ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, fmt,
> &crtc_state->adjusted_mode);
> if (ret)
> @@ -998,16 +977,16 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> 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;
> const struct drm_crtc_state *crtc_state = NULL;
>
> if (new_plane_state->crtc)
> crtc_state = drm_atomic_get_new_crtc_state(state,
> new_plane_state->crtc);
>
> - if (pdpu->pipe != SSPP_NONE) {
> - pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
> - r_pipe->sspp = NULL;
> - }
> + pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
> + r_pipe->sspp = NULL;
>
> if (!pipe->sspp)
> return -EINVAL;
> @@ -1019,6 +998,52 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> if (!new_plane_state->visible)
> return 0;
>
> + 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;
> +
> + if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) {
> + uint32_t max_linewidth = dpu_kms->catalog->caps->max_linewidth;
> + const struct dpu_format *fmt;
> +
> + fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
> +
> + /*
> + * In parallel multirect case only the half of the usual width
> + * is supported for tiled formats. If we are here, we know that
> + * full width is more than max_linewidth, thus each rect is
> + * wider than allowed.
> + */
> + if (DPU_FORMAT_IS_UBWC(fmt) &&
> + drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) {
> + DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u, tiled format\n",
> + DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);
> + return -E2BIG;
> + }
> +
> + r_pipe->sspp = pipe->sspp;
> +
> + if (!dpu_plane_is_multirect_parallel_capable(pipe, pipe_cfg, fmt, max_linewidth) ||
> + !dpu_plane_is_multirect_parallel_capable(r_pipe, r_pipe_cfg, fmt, max_linewidth) ||
> + !(test_bit(DPU_SSPP_SMART_DMA_V1, &pipe->sspp->cap->features) ||
> + test_bit(DPU_SSPP_SMART_DMA_V2, &pipe->sspp->cap->features))) {
> + 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;
> + }
> +
> + /*
> + * 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->multirect_index = DPU_SSPP_RECT_1;
> + r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
> + }
> +
I might be wrong here, but it seems like this part was moved to
dpu_plane_atomic_check_nopipe() in patch 6 and now being brought back
(atleast most of it) to dpu_plane_atomic_check().
If this is correct, then the migration in patch 6 was not necessary.
> return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
> }
>
> @@ -1053,10 +1078,18 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
>
> format = to_dpu_format(msm_framebuffer_format(plane_state->fb));
>
> - /* force resource reallocation if the format of FB has changed */
> - if (pstate->saved_fmt != format) {
> + /* force resource reallocation if the format of FB or src/dst have changed */
> + if (pstate->saved_fmt != format ||
> + pstate->saved_src_w != plane_state->src_w ||
> + pstate->saved_src_h != plane_state->src_h ||
> + pstate->saved_src_w != plane_state->src_w ||
> + pstate->saved_crtc_h != plane_state->crtc_h) {
> crtc_state->planes_changed = true;
> pstate->saved_fmt = format;
> + pstate->saved_src_w = plane_state->src_w;
> + pstate->saved_src_h = plane_state->src_h;
> + pstate->saved_crtc_w = plane_state->crtc_w;
> + pstate->saved_crtc_h = plane_state->crtc_h;
> }
Is thic chunk checking that if the src/dst have changed, this plane
might span more than one LM?
Will be better to add more comment on why we are also checking src/dest
changes.
Overall, can we just use for_each_oldnew_plane_in_state to compare the
prev and current dimensions and drop saved_****?
>
> return 0;
> @@ -1074,7 +1107,10 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
> struct dpu_plane_state *pstate;
> 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 dpu_format *fmt;
> + uint32_t max_linewidth;
>
> if (plane_state->crtc)
> crtc_state = drm_atomic_get_new_crtc_state(state,
> @@ -1083,6 +1119,8 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
> pstate = to_dpu_plane_state(plane_state);
> 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;
> @@ -1097,10 +1135,46 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
>
> reqs.rot90 = drm_rotation_90_or_270(plane_state->rotation);
>
> + max_linewidth = dpu_kms->catalog->caps->max_linewidth;
> +
> pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
> if (!pipe->sspp)
> return -ENODEV;
>
> + if (drm_rect_width(&r_pipe_cfg->src_rect) == 0) {
> + 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;
> + } else {
> + if (dpu_plane_is_multirect_parallel_capable(pipe, pipe_cfg, fmt, max_linewidth) &&
> + dpu_plane_is_multirect_parallel_capable(r_pipe, r_pipe_cfg, fmt, max_linewidth) &&
> + (test_bit(DPU_SSPP_SMART_DMA_V1, &pipe->sspp->cap->features) ||
> + test_bit(DPU_SSPP_SMART_DMA_V2, &pipe->sspp->cap->features))) {
> + r_pipe->sspp = pipe->sspp;
> +
> + pipe->multirect_index = DPU_SSPP_RECT_0;
> + pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
> +
> + r_pipe->multirect_index = DPU_SSPP_RECT_1;
> + r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
> + } else {
> + /* 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;
> + }
> + }
> +
This chunk LGTM.
> return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
> }
>
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> index 15f7d60d8b85..5522f9035d68 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> @@ -31,6 +31,10 @@
> * @plane_clk: calculated clk per plane
> * @needs_dirtyfb: whether attached CRTC needs pixel data explicitly flushed
> * @saved_fmt: format used by the plane's FB, saved for for virtual plane support
> + * @saved_src_w: cached value of plane's src_w, saved for for virtual plane support
> + * @saved_src_h: cached value of plane's src_h, saved for for virtual plane support
> + * @saved_crtc_w: cached value of plane's crtc_w, saved for for virtual plane support
> + * @saved_crtc_h: cached value of plane's crtc_h, saved for for virtual plane support
> */
> struct dpu_plane_state {
> struct drm_plane_state base;
> @@ -49,6 +53,10 @@ struct dpu_plane_state {
> bool needs_dirtyfb;
>
> const struct dpu_format *saved_fmt;
> + uint32_t saved_src_w;
> + uint32_t saved_src_h;
> + uint32_t saved_crtc_w;
> + uint32_t saved_crtc_h;
> };
>
> #define to_dpu_plane_state(x) \
^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v4 10/13] drm/msm/dpu: allow sharing SSPP between planes
2024-03-14 0:02 [PATCH v4 00/13] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
` (8 preceding siblings ...)
2024-03-14 0:02 ` [PATCH v4 09/13] drm/msm/dpu: allow using two SSPP blocks for a single plane Dmitry Baryshkov
@ 2024-03-14 0:02 ` Dmitry Baryshkov
2024-06-11 23:12 ` Abhinav Kumar
2024-03-14 0:02 ` [PATCH v4 11/13] drm/msm/dpu: create additional virtual planes Dmitry Baryshkov
` (3 subsequent siblings)
13 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-03-14 0:02 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Abhinav Kumar, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
Since SmartDMA planes provide two rectangles, it is possible to use them
to drive two different DRM planes, first plane getting the rect_0,
another one using rect_1 of the same SSPP. The sharing algorithm is
pretty simple, it requires that each of the planes can be driven by the
single rectangle and only consequetive planes are considered.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 128 +++++++++++++++++++---
1 file changed, 112 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index cde20c1fa90d..2e1c544efc4a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -886,10 +886,9 @@ static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
return 0;
}
-static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
- struct dpu_sw_pipe_cfg *pipe_cfg,
- const struct dpu_format *fmt,
- uint32_t max_linewidth)
+static int dpu_plane_is_multirect_capable(struct dpu_sw_pipe *pipe,
+ struct dpu_sw_pipe_cfg *pipe_cfg,
+ const struct dpu_format *fmt)
{
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))
@@ -901,6 +900,13 @@ static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
if (DPU_FORMAT_IS_YUV(fmt))
return false;
+ return true;
+}
+
+static int dpu_plane_is_parallel_capable(struct dpu_sw_pipe_cfg *pipe_cfg,
+ const struct dpu_format *fmt,
+ uint32_t max_linewidth)
+{
if (DPU_FORMAT_IS_UBWC(fmt) &&
drm_rect_width(&pipe_cfg->src_rect) > max_linewidth / 2)
return false;
@@ -908,6 +914,82 @@ static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
return true;
}
+static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
+ struct dpu_sw_pipe_cfg *pipe_cfg,
+ const struct dpu_format *fmt,
+ uint32_t max_linewidth)
+{
+ return dpu_plane_is_multirect_capable(pipe, pipe_cfg, fmt) &&
+ dpu_plane_is_parallel_capable(pipe_cfg, fmt, max_linewidth);
+}
+
+
+static int dpu_plane_try_multirect(struct dpu_plane_state *pstate,
+ struct dpu_plane_state *prev_pstate,
+ const struct dpu_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_pstate->pipe;
+ struct dpu_sw_pipe_cfg *prev_pipe_cfg = &prev_pstate->pipe_cfg;
+ const struct dpu_format *prev_fmt =
+ to_dpu_format(msm_framebuffer_format(prev_pstate->base.fb));
+ u16 max_tile_height = 1;
+
+ if (prev_pstate->r_pipe.sspp != NULL ||
+ prev_pipe->multirect_mode != DPU_SSPP_MULTIRECT_NONE)
+ return false;
+
+ if (!dpu_plane_is_multirect_capable(pipe, pipe_cfg, fmt) ||
+ !dpu_plane_is_multirect_capable(prev_pipe, prev_pipe_cfg, prev_fmt) ||
+ !(test_bit(DPU_SSPP_SMART_DMA_V1, &prev_pipe->sspp->cap->features) ||
+ test_bit(DPU_SSPP_SMART_DMA_V2, &prev_pipe->sspp->cap->features)))
+ return false;
+
+ if (DPU_FORMAT_IS_UBWC(fmt))
+ max_tile_height = max(max_tile_height, fmt->tile_height);
+
+ if (DPU_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 ||
+ prev_pipe_cfg->dst_rect.x1 >= pipe_cfg->dst_rect.x2)) {
+ pipe->sspp = prev_pipe->sspp;
+
+ pipe->multirect_index = DPU_SSPP_RECT_1;
+ pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
+
+ prev_pipe->multirect_index = DPU_SSPP_RECT_0;
+ prev_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
+
+ return true;
+ }
+
+ if (pipe_cfg->dst_rect.y1 >= prev_pipe_cfg->dst_rect.y2 + 2 * max_tile_height ||
+ prev_pipe_cfg->dst_rect.y1 >= pipe_cfg->dst_rect.y2 + 2 * max_tile_height) {
+ pipe->sspp = prev_pipe->sspp;
+
+ pipe->multirect_index = DPU_SSPP_RECT_1;
+ pipe->multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX;
+
+ prev_pipe->multirect_index = DPU_SSPP_RECT_0;
+ prev_pipe->multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX;
+
+ return true;
+ }
+
+ return false;
+}
+
static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
struct drm_atomic_state *state,
const struct drm_crtc_state *crtc_state)
@@ -1098,13 +1180,14 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
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 *plane_state,
+ struct drm_plane_state *prev_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;
+ struct dpu_plane_state *pstate, *prev_pstate;
struct dpu_sw_pipe *pipe;
struct dpu_sw_pipe *r_pipe;
struct dpu_sw_pipe_cfg *pipe_cfg;
@@ -1117,6 +1200,7 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
plane_state->crtc);
pstate = to_dpu_plane_state(plane_state);
+ prev_pstate = prev_plane_state ? to_dpu_plane_state(prev_plane_state) : NULL;
pipe = &pstate->pipe;
r_pipe = &pstate->r_pipe;
pipe_cfg = &pstate->pipe_cfg;
@@ -1137,19 +1221,27 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
max_linewidth = dpu_kms->catalog->caps->max_linewidth;
- pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
- if (!pipe->sspp)
- return -ENODEV;
-
if (drm_rect_width(&r_pipe_cfg->src_rect) == 0) {
- pipe->multirect_index = DPU_SSPP_RECT_SOLO;
- pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
+ if (!prev_pstate ||
+ !dpu_plane_try_multirect(pstate, prev_pstate, fmt, max_linewidth)) {
+ pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
+ if (!pipe->sspp)
+ return -ENODEV;
- r_pipe->multirect_index = DPU_SSPP_RECT_SOLO;
- r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
+ r_pipe->sspp = NULL;
+
+ 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;
} else {
+ pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
+ if (!pipe->sspp)
+ return -ENODEV;
+
if (dpu_plane_is_multirect_parallel_capable(pipe, pipe_cfg, fmt, max_linewidth) &&
dpu_plane_is_multirect_parallel_capable(r_pipe, r_pipe_cfg, fmt, max_linewidth) &&
(test_bit(DPU_SSPP_SMART_DMA_V1, &pipe->sspp->cap->features) ||
@@ -1186,6 +1278,7 @@ int dpu_assign_plane_resources(struct dpu_global_state *global_state,
{
unsigned int i;
int ret;
+ struct drm_plane_state *prev_plane_state = NULL;
for (i = 0; i < num_planes; i++) {
struct drm_plane_state *plane_state = states[i];
@@ -1195,9 +1288,12 @@ int dpu_assign_plane_resources(struct dpu_global_state *global_state,
continue;
ret = dpu_plane_virtual_assign_resources(crtc, global_state,
- state, plane_state);
+ state, plane_state,
+ prev_plane_state);
if (ret)
break;
+
+ prev_plane_state = plane_state;
}
return ret;
--
2.39.2
^ permalink raw reply related [flat|nested] 50+ messages in thread* Re: [PATCH v4 10/13] drm/msm/dpu: allow sharing SSPP between planes
2024-03-14 0:02 ` [PATCH v4 10/13] drm/msm/dpu: allow sharing SSPP between planes Dmitry Baryshkov
@ 2024-06-11 23:12 ` Abhinav Kumar
2024-06-12 9:08 ` Dmitry Baryshkov
0 siblings, 1 reply; 50+ messages in thread
From: Abhinav Kumar @ 2024-06-11 23:12 UTC (permalink / raw)
To: Dmitry Baryshkov, Rob Clark, Sean Paul, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> Since SmartDMA planes provide two rectangles, it is possible to use them
> to drive two different DRM planes, first plane getting the rect_0,
> another one using rect_1 of the same SSPP. The sharing algorithm is
> pretty simple, it requires that each of the planes can be driven by the
> single rectangle and only consequetive planes are considered.
>
consequetive - > consecutive
Can you please explain why only consecutive planes are considered for this?
So lets say we have 4 virtual planes : 0, 1, 2, 3
It will try 0-1, 1-2, 2-3
Because all planes are virtual, there are only 3 unique pairs to be
considered? Otherwise technically 6 pairs are possible.
General request:
Patches 1-9 : Add support for using 2 SSPPs in one plane
Patches 10-12 : Add support for using two rectangles of the same SSPP as
two virtual planes
Patch 13 : Can be pushed along with the first set.
Can we break up this series in this way to make it easier to test and
land the bulk of it in this cycle?
I have some doubts on patches 10-12 and would like to spend more time
reviewing and testing this. So I am trying to reduce the debt of patches
we have been carrying as this is a tricky feature to simulate and test
the cases.
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 128 +++++++++++++++++++---
> 1 file changed, 112 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> index cde20c1fa90d..2e1c544efc4a 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> @@ -886,10 +886,9 @@ static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
> return 0;
> }
>
> -static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
> - struct dpu_sw_pipe_cfg *pipe_cfg,
> - const struct dpu_format *fmt,
> - uint32_t max_linewidth)
> +static int dpu_plane_is_multirect_capable(struct dpu_sw_pipe *pipe,
> + struct dpu_sw_pipe_cfg *pipe_cfg,
> + const struct dpu_format *fmt)
> {
> 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))
> @@ -901,6 +900,13 @@ static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
> if (DPU_FORMAT_IS_YUV(fmt))
> return false;
>
> + return true;
> +}
> +
> +static int dpu_plane_is_parallel_capable(struct dpu_sw_pipe_cfg *pipe_cfg,
> + const struct dpu_format *fmt,
> + uint32_t max_linewidth)
> +{
> if (DPU_FORMAT_IS_UBWC(fmt) &&
> drm_rect_width(&pipe_cfg->src_rect) > max_linewidth / 2)
> return false;
> @@ -908,6 +914,82 @@ static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
> return true;
> }
>
> +static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
> + struct dpu_sw_pipe_cfg *pipe_cfg,
> + const struct dpu_format *fmt,
> + uint32_t max_linewidth)
> +{
> + return dpu_plane_is_multirect_capable(pipe, pipe_cfg, fmt) &&
> + dpu_plane_is_parallel_capable(pipe_cfg, fmt, max_linewidth);
> +}
> +
> +
> +static int dpu_plane_try_multirect(struct dpu_plane_state *pstate,
> + struct dpu_plane_state *prev_pstate,
> + const struct dpu_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_pstate->pipe;
> + struct dpu_sw_pipe_cfg *prev_pipe_cfg = &prev_pstate->pipe_cfg;
> + const struct dpu_format *prev_fmt =
> + to_dpu_format(msm_framebuffer_format(prev_pstate->base.fb));
> + u16 max_tile_height = 1;
> +
> + if (prev_pstate->r_pipe.sspp != NULL ||
> + prev_pipe->multirect_mode != DPU_SSPP_MULTIRECT_NONE)
> + return false;
> +
> + if (!dpu_plane_is_multirect_capable(pipe, pipe_cfg, fmt) ||
> + !dpu_plane_is_multirect_capable(prev_pipe, prev_pipe_cfg, prev_fmt) ||
> + !(test_bit(DPU_SSPP_SMART_DMA_V1, &prev_pipe->sspp->cap->features) ||
> + test_bit(DPU_SSPP_SMART_DMA_V2, &prev_pipe->sspp->cap->features)))
This test_bit check should be absorbed into
dpu_plane_is_multirect_capable()?
> + return false;
> +
> + if (DPU_FORMAT_IS_UBWC(fmt))
> + max_tile_height = max(max_tile_height, fmt->tile_height);
> +
> + if (DPU_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 ||
> + prev_pipe_cfg->dst_rect.x1 >= pipe_cfg->dst_rect.x2)) {
Even if y1 > y2 or y2 > y1 but the separation is less than the 2 *
max_tile_height, it can qualify for parallel fetch.
So parallel fetch is possible not only in x direction but y direction as
well as it will be fetched by different SSPPs.
> + pipe->sspp = prev_pipe->sspp;
> +
> + pipe->multirect_index = DPU_SSPP_RECT_1;
> + pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
> +
> + prev_pipe->multirect_index = DPU_SSPP_RECT_0;
> + prev_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
> +
> + return true;
> + }
> +
> + if (pipe_cfg->dst_rect.y1 >= prev_pipe_cfg->dst_rect.y2 + 2 * max_tile_height ||
> + prev_pipe_cfg->dst_rect.y1 >= pipe_cfg->dst_rect.y2 + 2 * max_tile_height) {
> + pipe->sspp = prev_pipe->sspp;
> +
> + pipe->multirect_index = DPU_SSPP_RECT_1;
> + pipe->multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX;
> +
> + prev_pipe->multirect_index = DPU_SSPP_RECT_0;
> + prev_pipe->multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX;
> +
> + return true;
> + }
> +
> + return false;
> +}
> +
> static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
> struct drm_atomic_state *state,
> const struct drm_crtc_state *crtc_state)
> @@ -1098,13 +1180,14 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
> 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 *plane_state,
> + struct drm_plane_state *prev_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;
> + struct dpu_plane_state *pstate, *prev_pstate;
> struct dpu_sw_pipe *pipe;
> struct dpu_sw_pipe *r_pipe;
> struct dpu_sw_pipe_cfg *pipe_cfg;
> @@ -1117,6 +1200,7 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
> plane_state->crtc);
>
> pstate = to_dpu_plane_state(plane_state);
> + prev_pstate = prev_plane_state ? to_dpu_plane_state(prev_plane_state) : NULL;
> pipe = &pstate->pipe;
> r_pipe = &pstate->r_pipe;
> pipe_cfg = &pstate->pipe_cfg;
> @@ -1137,19 +1221,27 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
>
> max_linewidth = dpu_kms->catalog->caps->max_linewidth;
>
> - pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
> - if (!pipe->sspp)
> - return -ENODEV;
> -
> if (drm_rect_width(&r_pipe_cfg->src_rect) == 0) {
> - pipe->multirect_index = DPU_SSPP_RECT_SOLO;
> - pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
> + if (!prev_pstate ||
> + !dpu_plane_try_multirect(pstate, prev_pstate, fmt, max_linewidth)) {
This is a bit confusing to check esp since i am unable to apply this
patch and check .... but...
dpu_plane_atomic_check_nopipe() will set r_pipe_cfg if we are going to
do multirect with two rectangles of the same sspp. Right?
Which means r_pipe_cfg will be 0 if multirect is not possible with same
SSPP. Thats why the else case of this either uses two SSPPs.
So why are we trying multirect with again with the two rectangles of the
same SSPP as different planes? The result will be same right?
> + pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
> + if (!pipe->sspp)
> + return -ENODEV;
>
> - r_pipe->multirect_index = DPU_SSPP_RECT_SOLO;
> - r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
> + r_pipe->sspp = NULL;
> +
> + 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;
> } else {
> + pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
> + if (!pipe->sspp)
> + return -ENODEV;
> +
Unless I am missing something, you are assigning pipe->sspp in both if
and else cases, so why dont you keep the allocation if pipe->sspp
outside the conditionals.
> if (dpu_plane_is_multirect_parallel_capable(pipe, pipe_cfg, fmt, max_linewidth) &&
> dpu_plane_is_multirect_parallel_capable(r_pipe, r_pipe_cfg, fmt, max_linewidth) &&
> (test_bit(DPU_SSPP_SMART_DMA_V1, &pipe->sspp->cap->features) ||
> @@ -1186,6 +1278,7 @@ int dpu_assign_plane_resources(struct dpu_global_state *global_state,
> {
> unsigned int i;
> int ret;
> + struct drm_plane_state *prev_plane_state = NULL;
>
This naming is a bit confusing. prev_plane_state could mean the plane's
previous state but here you are implying the state of the previous plane
in the list of planes.
Maybe prev_adjacent_plane_state?
> for (i = 0; i < num_planes; i++) {
> struct drm_plane_state *plane_state = states[i];
> @@ -1195,9 +1288,12 @@ int dpu_assign_plane_resources(struct dpu_global_state *global_state,
> continue;
>
> ret = dpu_plane_virtual_assign_resources(crtc, global_state,
> - state, plane_state);
> + state, plane_state,
> + prev_plane_state);
> if (ret)
> break;
> +
> + prev_plane_state = plane_state;
> }
>
> return ret;
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 10/13] drm/msm/dpu: allow sharing SSPP between planes
2024-06-11 23:12 ` Abhinav Kumar
@ 2024-06-12 9:08 ` Dmitry Baryshkov
2024-06-13 1:17 ` Abhinav Kumar
0 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-06-12 9:08 UTC (permalink / raw)
To: Abhinav Kumar
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On Wed, 12 Jun 2024 at 02:12, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>
>
>
> On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> > Since SmartDMA planes provide two rectangles, it is possible to use them
> > to drive two different DRM planes, first plane getting the rect_0,
> > another one using rect_1 of the same SSPP. The sharing algorithm is
> > pretty simple, it requires that each of the planes can be driven by the
> > single rectangle and only consequetive planes are considered.
> >
>
> consequetive - > consecutive
>
> Can you please explain why only consecutive planes are considered for this?
>
> So lets say we have 4 virtual planes : 0, 1, 2, 3
>
> It will try 0-1, 1-2, 2-3
>
> Because all planes are virtual, there are only 3 unique pairs to be
> considered? Otherwise technically 6 pairs are possible.
An implementation that tries all 6 pairs taking the zpos and the
overlapping into account is appreciated. I cared for the simplest case
here. Yes, further optimizations can be implemented.
>
>
> General request:
>
> Patches 1-9 : Add support for using 2 SSPPs in one plane
> Patches 10-12 : Add support for using two rectangles of the same SSPP as
> two virtual planes
> Patch 13 : Can be pushed along with the first set.
>
> Can we break up this series in this way to make it easier to test and
> land the bulk of it in this cycle?
Sure.
>
> I have some doubts on patches 10-12 and would like to spend more time
> reviewing and testing this. So I am trying to reduce the debt of patches
> we have been carrying as this is a tricky feature to simulate and test
> the cases.
>
> > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > ---
> > drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 128 +++++++++++++++++++---
> > 1 file changed, 112 insertions(+), 16 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > index cde20c1fa90d..2e1c544efc4a 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > @@ -886,10 +886,9 @@ static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
> > return 0;
> > }
> >
> > -static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
> > - struct dpu_sw_pipe_cfg *pipe_cfg,
> > - const struct dpu_format *fmt,
> > - uint32_t max_linewidth)
> > +static int dpu_plane_is_multirect_capable(struct dpu_sw_pipe *pipe,
> > + struct dpu_sw_pipe_cfg *pipe_cfg,
> > + const struct dpu_format *fmt)
> > {
> > 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))
> > @@ -901,6 +900,13 @@ static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
> > if (DPU_FORMAT_IS_YUV(fmt))
> > return false;
> >
> > + return true;
> > +}
> > +
> > +static int dpu_plane_is_parallel_capable(struct dpu_sw_pipe_cfg *pipe_cfg,
> > + const struct dpu_format *fmt,
> > + uint32_t max_linewidth)
> > +{
> > if (DPU_FORMAT_IS_UBWC(fmt) &&
> > drm_rect_width(&pipe_cfg->src_rect) > max_linewidth / 2)
> > return false;
> > @@ -908,6 +914,82 @@ static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
> > return true;
> > }
> >
> > +static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
> > + struct dpu_sw_pipe_cfg *pipe_cfg,
> > + const struct dpu_format *fmt,
> > + uint32_t max_linewidth)
> > +{
> > + return dpu_plane_is_multirect_capable(pipe, pipe_cfg, fmt) &&
> > + dpu_plane_is_parallel_capable(pipe_cfg, fmt, max_linewidth);
> > +}
> > +
> > +
> > +static int dpu_plane_try_multirect(struct dpu_plane_state *pstate,
> > + struct dpu_plane_state *prev_pstate,
> > + const struct dpu_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_pstate->pipe;
> > + struct dpu_sw_pipe_cfg *prev_pipe_cfg = &prev_pstate->pipe_cfg;
> > + const struct dpu_format *prev_fmt =
> > + to_dpu_format(msm_framebuffer_format(prev_pstate->base.fb));
> > + u16 max_tile_height = 1;
> > +
> > + if (prev_pstate->r_pipe.sspp != NULL ||
> > + prev_pipe->multirect_mode != DPU_SSPP_MULTIRECT_NONE)
> > + return false;
> > +
> > + if (!dpu_plane_is_multirect_capable(pipe, pipe_cfg, fmt) ||
> > + !dpu_plane_is_multirect_capable(prev_pipe, prev_pipe_cfg, prev_fmt) ||
> > + !(test_bit(DPU_SSPP_SMART_DMA_V1, &prev_pipe->sspp->cap->features) ||
> > + test_bit(DPU_SSPP_SMART_DMA_V2, &prev_pipe->sspp->cap->features)))
>
> This test_bit check should be absorbed into
> dpu_plane_is_multirect_capable()?
Yep.
>
> > + return false;
> > +
> > + if (DPU_FORMAT_IS_UBWC(fmt))
> > + max_tile_height = max(max_tile_height, fmt->tile_height);
> > +
> > + if (DPU_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 ||
> > + prev_pipe_cfg->dst_rect.x1 >= pipe_cfg->dst_rect.x2)) {
>
> Even if y1 > y2 or y2 > y1 but the separation is less than the 2 *
> max_tile_height, it can qualify for parallel fetch.
>
> So parallel fetch is possible not only in x direction but y direction as
> well as it will be fetched by different SSPPs.
I think that's now what I see in the SDE driver.
>
> > + pipe->sspp = prev_pipe->sspp;
> > +
> > + pipe->multirect_index = DPU_SSPP_RECT_1;
> > + pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
> > +
> > + prev_pipe->multirect_index = DPU_SSPP_RECT_0;
> > + prev_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
> > +
> > + return true;
> > + }
> > +
> > + if (pipe_cfg->dst_rect.y1 >= prev_pipe_cfg->dst_rect.y2 + 2 * max_tile_height ||
> > + prev_pipe_cfg->dst_rect.y1 >= pipe_cfg->dst_rect.y2 + 2 * max_tile_height) {
> > + pipe->sspp = prev_pipe->sspp;
> > +
> > + pipe->multirect_index = DPU_SSPP_RECT_1;
> > + pipe->multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX;
> > +
> > + prev_pipe->multirect_index = DPU_SSPP_RECT_0;
> > + prev_pipe->multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX;
> > +
> > + return true;
> > + }
> > +
> > + return false;
> > +}
> > +
> > static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
> > struct drm_atomic_state *state,
> > const struct drm_crtc_state *crtc_state)
> > @@ -1098,13 +1180,14 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
> > 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 *plane_state,
> > + struct drm_plane_state *prev_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;
> > + struct dpu_plane_state *pstate, *prev_pstate;
> > struct dpu_sw_pipe *pipe;
> > struct dpu_sw_pipe *r_pipe;
> > struct dpu_sw_pipe_cfg *pipe_cfg;
> > @@ -1117,6 +1200,7 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
> > plane_state->crtc);
> >
> > pstate = to_dpu_plane_state(plane_state);
> > + prev_pstate = prev_plane_state ? to_dpu_plane_state(prev_plane_state) : NULL;
> > pipe = &pstate->pipe;
> > r_pipe = &pstate->r_pipe;
> > pipe_cfg = &pstate->pipe_cfg;
> > @@ -1137,19 +1221,27 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
> >
> > max_linewidth = dpu_kms->catalog->caps->max_linewidth;
> >
> > - pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
> > - if (!pipe->sspp)
> > - return -ENODEV;
> > -
> > if (drm_rect_width(&r_pipe_cfg->src_rect) == 0) {
> > - pipe->multirect_index = DPU_SSPP_RECT_SOLO;
> > - pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
> > + if (!prev_pstate ||
> > + !dpu_plane_try_multirect(pstate, prev_pstate, fmt, max_linewidth)) {
>
> This is a bit confusing to check esp since i am unable to apply this
> patch and check .... but...
It was posted several months ago. No surprise that the source code has
evolved. Getting the patches reviewed in time would have helped them
to be applicable.
> dpu_plane_atomic_check_nopipe() will set r_pipe_cfg if we are going to
> do multirect with two rectangles of the same sspp. Right?
No. It sets r_pipe_cfg in all the cases.
> Which means r_pipe_cfg will be 0 if multirect is not possible with same
> SSPP. Thats why the else case of this either uses two SSPPs.
No. It means that the plane can use a single rectangle of the SSPP.
>
> So why are we trying multirect with again with the two rectangles of the
> same SSPP as different planes? The result will be same right?
No, if the width of r_pipe_cfg is 0, it means that this plane doesn't
need a second rectangle to be displayed. So we can try reusing the
SSPP from the previous plane.
>
>
> > + pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
> > + if (!pipe->sspp)
> > + return -ENODEV;
> >
> > - r_pipe->multirect_index = DPU_SSPP_RECT_SOLO;
> > - r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
> > + r_pipe->sspp = NULL;
> > +
> > + 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;
> > } else {
> > + pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
> > + if (!pipe->sspp)
> > + return -ENODEV;
> > +
>
> Unless I am missing something, you are assigning pipe->sspp in both if
> and else cases, so why dont you keep the allocation if pipe->sspp
> outside the conditionals.
You missed the conditional in the previous chunk. We need to reserve
SSPP if the plane uses two rectangles. We don't need to reserve an
SSPP if the old SSPP is going to be used.
>
> > if (dpu_plane_is_multirect_parallel_capable(pipe, pipe_cfg, fmt, max_linewidth) &&
> > dpu_plane_is_multirect_parallel_capable(r_pipe, r_pipe_cfg, fmt, max_linewidth) &&
> > (test_bit(DPU_SSPP_SMART_DMA_V1, &pipe->sspp->cap->features) ||
> > @@ -1186,6 +1278,7 @@ int dpu_assign_plane_resources(struct dpu_global_state *global_state,
> > {
> > unsigned int i;
> > int ret;
> > + struct drm_plane_state *prev_plane_state = NULL;
> >
>
> This naming is a bit confusing. prev_plane_state could mean the plane's
> previous state but here you are implying the state of the previous plane
> in the list of planes.
>
> Maybe prev_adjacent_plane_state?
Ack.
>
> > for (i = 0; i < num_planes; i++) {
> > struct drm_plane_state *plane_state = states[i];
> > @@ -1195,9 +1288,12 @@ int dpu_assign_plane_resources(struct dpu_global_state *global_state,
> > continue;
> >
> > ret = dpu_plane_virtual_assign_resources(crtc, global_state,
> > - state, plane_state);
> > + state, plane_state,
> > + prev_plane_state);
> > if (ret)
> > break;
> > +
> > + prev_plane_state = plane_state;
> > }
> >
> > return ret;
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 10/13] drm/msm/dpu: allow sharing SSPP between planes
2024-06-12 9:08 ` Dmitry Baryshkov
@ 2024-06-13 1:17 ` Abhinav Kumar
2024-06-13 10:05 ` Dmitry Baryshkov
0 siblings, 1 reply; 50+ messages in thread
From: Abhinav Kumar @ 2024-06-13 1:17 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On 6/12/2024 2:08 AM, Dmitry Baryshkov wrote:
> On Wed, 12 Jun 2024 at 02:12, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>>
>>
>>
>> On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
>>> Since SmartDMA planes provide two rectangles, it is possible to use them
>>> to drive two different DRM planes, first plane getting the rect_0,
>>> another one using rect_1 of the same SSPP. The sharing algorithm is
>>> pretty simple, it requires that each of the planes can be driven by the
>>> single rectangle and only consequetive planes are considered.
>>>
>>
>> consequetive - > consecutive
>>
>> Can you please explain why only consecutive planes are considered for this?
>>
>> So lets say we have 4 virtual planes : 0, 1, 2, 3
>>
>> It will try 0-1, 1-2, 2-3
>>
>> Because all planes are virtual, there are only 3 unique pairs to be
>> considered? Otherwise technically 6 pairs are possible.
>
> An implementation that tries all 6 pairs taking the zpos and the
> overlapping into account is appreciated. I cared for the simplest case
> here. Yes, further optimizations can be implemented.
>
Ok got it. So you would like to build a better one on top of this.
But I see one case where this has an issue or is not optimal. Pls see below.
>>
>>
>> General request:
>>
>> Patches 1-9 : Add support for using 2 SSPPs in one plane
>> Patches 10-12 : Add support for using two rectangles of the same SSPP as
>> two virtual planes
>> Patch 13 : Can be pushed along with the first set.
>>
>> Can we break up this series in this way to make it easier to test and
>> land the bulk of it in this cycle?
>
> Sure.
>
Thanks.
>>
>> I have some doubts on patches 10-12 and would like to spend more time
>> reviewing and testing this. So I am trying to reduce the debt of patches
>> we have been carrying as this is a tricky feature to simulate and test
>> the cases.
>>
>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>> ---
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 128 +++++++++++++++++++---
>>> 1 file changed, 112 insertions(+), 16 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>> index cde20c1fa90d..2e1c544efc4a 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>> @@ -886,10 +886,9 @@ static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
>>> return 0;
>>> }
>>>
>>> -static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
>>> - struct dpu_sw_pipe_cfg *pipe_cfg,
>>> - const struct dpu_format *fmt,
>>> - uint32_t max_linewidth)
>>> +static int dpu_plane_is_multirect_capable(struct dpu_sw_pipe *pipe,
>>> + struct dpu_sw_pipe_cfg *pipe_cfg,
>>> + const struct dpu_format *fmt)
>>> {
>>> 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))
>>> @@ -901,6 +900,13 @@ static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
>>> if (DPU_FORMAT_IS_YUV(fmt))
>>> return false;
>>>
>>> + return true;
>>> +}
>>> +
>>> +static int dpu_plane_is_parallel_capable(struct dpu_sw_pipe_cfg *pipe_cfg,
>>> + const struct dpu_format *fmt,
>>> + uint32_t max_linewidth)
>>> +{
>>> if (DPU_FORMAT_IS_UBWC(fmt) &&
>>> drm_rect_width(&pipe_cfg->src_rect) > max_linewidth / 2)
>>> return false;
>>> @@ -908,6 +914,82 @@ static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
>>> return true;
>>> }
>>>
>>> +static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
>>> + struct dpu_sw_pipe_cfg *pipe_cfg,
>>> + const struct dpu_format *fmt,
>>> + uint32_t max_linewidth)
>>> +{
>>> + return dpu_plane_is_multirect_capable(pipe, pipe_cfg, fmt) &&
>>> + dpu_plane_is_parallel_capable(pipe_cfg, fmt, max_linewidth);
>>> +}
>>> +
>>> +
>>> +static int dpu_plane_try_multirect(struct dpu_plane_state *pstate,
>>> + struct dpu_plane_state *prev_pstate,
>>> + const struct dpu_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_pstate->pipe;
>>> + struct dpu_sw_pipe_cfg *prev_pipe_cfg = &prev_pstate->pipe_cfg;
>>> + const struct dpu_format *prev_fmt =
>>> + to_dpu_format(msm_framebuffer_format(prev_pstate->base.fb));
>>> + u16 max_tile_height = 1;
>>> +
>>> + if (prev_pstate->r_pipe.sspp != NULL ||
>>> + prev_pipe->multirect_mode != DPU_SSPP_MULTIRECT_NONE)
>>> + return false;
>>> +
>>> + if (!dpu_plane_is_multirect_capable(pipe, pipe_cfg, fmt) ||
>>> + !dpu_plane_is_multirect_capable(prev_pipe, prev_pipe_cfg, prev_fmt) ||
>>> + !(test_bit(DPU_SSPP_SMART_DMA_V1, &prev_pipe->sspp->cap->features) ||
>>> + test_bit(DPU_SSPP_SMART_DMA_V2, &prev_pipe->sspp->cap->features)))
>>
>> This test_bit check should be absorbed into
>> dpu_plane_is_multirect_capable()?
>
> Yep.
>
>>
>>> + return false;
>>> +
>>> + if (DPU_FORMAT_IS_UBWC(fmt))
>>> + max_tile_height = max(max_tile_height, fmt->tile_height);
>>> +
>>> + if (DPU_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 ||
>>> + prev_pipe_cfg->dst_rect.x1 >= pipe_cfg->dst_rect.x2)) {
>>
>> Even if y1 > y2 or y2 > y1 but the separation is less than the 2 *
>> max_tile_height, it can qualify for parallel fetch.
>>
>> So parallel fetch is possible not only in x direction but y direction as
>> well as it will be fetched by different SSPPs.
>
> I think that's now what I see in the SDE driver.
>
hmm , okay, we can support that case once this one works without issues.
>>
>>> + pipe->sspp = prev_pipe->sspp;
>>> +
>>> + pipe->multirect_index = DPU_SSPP_RECT_1;
>>> + pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
>>> +
>>> + prev_pipe->multirect_index = DPU_SSPP_RECT_0;
>>> + prev_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
>>> +
>>> + return true;
>>> + }
>>> +
>>> + if (pipe_cfg->dst_rect.y1 >= prev_pipe_cfg->dst_rect.y2 + 2 * max_tile_height ||
>>> + prev_pipe_cfg->dst_rect.y1 >= pipe_cfg->dst_rect.y2 + 2 * max_tile_height) {
>>> + pipe->sspp = prev_pipe->sspp;
>>> +
>>> + pipe->multirect_index = DPU_SSPP_RECT_1;
>>> + pipe->multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX;
>>> +
>>> + prev_pipe->multirect_index = DPU_SSPP_RECT_0;
>>> + prev_pipe->multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX;
>>> +
>>> + return true;
>>> + }
>>> +
>>> + return false;
>>> +}
>>> +
>>> static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
>>> struct drm_atomic_state *state,
>>> const struct drm_crtc_state *crtc_state)
>>> @@ -1098,13 +1180,14 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
>>> 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 *plane_state,
>>> + struct drm_plane_state *prev_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;
>>> + struct dpu_plane_state *pstate, *prev_pstate;
>>> struct dpu_sw_pipe *pipe;
>>> struct dpu_sw_pipe *r_pipe;
>>> struct dpu_sw_pipe_cfg *pipe_cfg;
>>> @@ -1117,6 +1200,7 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
>>> plane_state->crtc);
>>>
>>> pstate = to_dpu_plane_state(plane_state);
>>> + prev_pstate = prev_plane_state ? to_dpu_plane_state(prev_plane_state) : NULL;
>>> pipe = &pstate->pipe;
>>> r_pipe = &pstate->r_pipe;
>>> pipe_cfg = &pstate->pipe_cfg;
>>> @@ -1137,19 +1221,27 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
>>>
>>> max_linewidth = dpu_kms->catalog->caps->max_linewidth;
>>>
>>> - pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
>>> - if (!pipe->sspp)
>>> - return -ENODEV;
>>> -
>>> if (drm_rect_width(&r_pipe_cfg->src_rect) == 0) {
>>> - pipe->multirect_index = DPU_SSPP_RECT_SOLO;
>>> - pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
>>> + if (!prev_pstate ||
>>> + !dpu_plane_try_multirect(pstate, prev_pstate, fmt, max_linewidth)) {
>>
>> This is a bit confusing to check esp since i am unable to apply this
>> patch and check .... but...
>
> It was posted several months ago. No surprise that the source code has
> evolved. Getting the patches reviewed in time would have helped them
> to be applicable.
>
Yes, part of the delays for virtual plane was purely because the CB
setup was down (both due to internal IT issues and general sc7280 being
down) and I want to make sure this series is compositor-tested and not
just modetest tested.
But anyway, thats why I didnt request a rebase this time even though it
was very hard to review the patch emails for this series.
>> dpu_plane_atomic_check_nopipe() will set r_pipe_cfg if we are going to
>> do multirect with two rectangles of the same sspp. Right?
>
> No. It sets r_pipe_cfg in all the cases.
>
From what I see, we still have this check before a valid rectangle is
set for the r_pipe_cfg
if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) ||
_dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) >
max_mdp_clk_rate) {
>> Which means r_pipe_cfg will be 0 if multirect is not possible with same
>> SSPP. Thats why the else case of this either uses two SSPPs.
>
> No. It means that the plane can use a single rectangle of the SSPP.
>
OR that the plane does not need to use multirect because its rectangle
width is < max_linewidth.
>>
>> So why are we trying multirect with again with the two rectangles of the
>> same SSPP as different planes? The result will be same right?
>
> No, if the width of r_pipe_cfg is 0, it means that this plane doesn't
> need a second rectangle to be displayed. So we can try reusing the
> SSPP from the previous plane.
>
Yes, agreed to this point that this plane doesnt need a second rectangle
to be displayed as it will fit in one rectangle.
And I see what you mean now, if the current plane needs only one
rectangle to be used, you are trying to use the prev plane's SSPP's
other rect?
So lets say we have plane 1 and plane 2 in the list.
Plane 1 has only one rect used and plane 2 also needs only one rect.
Then you use plane 1's SSPP even for plane 2.
Cant you use an alternative check like
!dpu_plane_is_wideplane_multirect() to make this condition clear?
Also dpu_plane_try_multirect() name is confusing then because you are
trying multi-rect again to see if the SSPP can be shared and wide-plane
multirect was not possible. So technically both are multirect, just
dfferent applications.
That will make it clear that you are trying to use multi-rect for
sharing SSPP.
So there are essentially two use-cases of multi-rect:
1) Wide plane multi-rect
2) SSPP sharing multi-rect
So this will make it clear.
Coming to the algorithm, I see one issue with this now.
Lets say we have this list of SSPPs.
DMA0 Vig0 Vig1
DMA0 has only rec0 used and rec1 is free.
Vig0 needs both recs used.
Vig1 needs only one rec.
Here it will notice that its previous plane has both rects used and will
not try the DMA0 even though it has one rect free and will end up using
a new SSPP.
Thats why considering only immediate pairs is not enough. All possible
pairs will address this.
>>
>>
>>> + pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
>>> + if (!pipe->sspp)
>>> + return -ENODEV;
>>>
>>> - r_pipe->multirect_index = DPU_SSPP_RECT_SOLO;
>>> - r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
>>> + r_pipe->sspp = NULL;
>>> +
>>> + 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;
>>> } else {
>>> + pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
>>> + if (!pipe->sspp)
>>> + return -ENODEV;
>>> +
>>
>> Unless I am missing something, you are assigning pipe->sspp in both if
>> and else cases, so why dont you keep the allocation if pipe->sspp
>> outside the conditionals.
>
> You missed the conditional in the previous chunk. We need to reserve
> SSPP if the plane uses two rectangles. We don't need to reserve an
> SSPP if the old SSPP is going to be used.
>
Ack.
>>
>>> if (dpu_plane_is_multirect_parallel_capable(pipe, pipe_cfg, fmt, max_linewidth) &&
>>> dpu_plane_is_multirect_parallel_capable(r_pipe, r_pipe_cfg, fmt, max_linewidth) &&
>>> (test_bit(DPU_SSPP_SMART_DMA_V1, &pipe->sspp->cap->features) ||
>>> @@ -1186,6 +1278,7 @@ int dpu_assign_plane_resources(struct dpu_global_state *global_state,
>>> {
>>> unsigned int i;
>>> int ret;
>>> + struct drm_plane_state *prev_plane_state = NULL;
>>>
>>
>> This naming is a bit confusing. prev_plane_state could mean the plane's
>> previous state but here you are implying the state of the previous plane
>> in the list of planes.
>>
>> Maybe prev_adjacent_plane_state?
>
> Ack.
>
>>
>>> for (i = 0; i < num_planes; i++) {
>>> struct drm_plane_state *plane_state = states[i];
>>> @@ -1195,9 +1288,12 @@ int dpu_assign_plane_resources(struct dpu_global_state *global_state,
>>> continue;
>>>
>>> ret = dpu_plane_virtual_assign_resources(crtc, global_state,
>>> - state, plane_state);
>>> + state, plane_state,
>>> + prev_plane_state);
>>> if (ret)
>>> break;
>>> +
>>> + prev_plane_state = plane_state;
>>> }
>>>
>>> return ret;
>
>
>
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 10/13] drm/msm/dpu: allow sharing SSPP between planes
2024-06-13 1:17 ` Abhinav Kumar
@ 2024-06-13 10:05 ` Dmitry Baryshkov
2024-06-13 20:02 ` Abhinav Kumar
0 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-06-13 10:05 UTC (permalink / raw)
To: Abhinav Kumar
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On Wed, Jun 12, 2024 at 06:17:37PM -0700, Abhinav Kumar wrote:
>
>
> On 6/12/2024 2:08 AM, Dmitry Baryshkov wrote:
> > On Wed, 12 Jun 2024 at 02:12, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
> > >
> > >
> > >
> > > On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> > > > Since SmartDMA planes provide two rectangles, it is possible to use them
> > > > to drive two different DRM planes, first plane getting the rect_0,
> > > > another one using rect_1 of the same SSPP. The sharing algorithm is
> > > > pretty simple, it requires that each of the planes can be driven by the
> > > > single rectangle and only consequetive planes are considered.
> > > >
> > >
> > > consequetive - > consecutive
> > >
> > > Can you please explain why only consecutive planes are considered for this?
> > >
> > > So lets say we have 4 virtual planes : 0, 1, 2, 3
> > >
> > > It will try 0-1, 1-2, 2-3
> > >
> > > Because all planes are virtual, there are only 3 unique pairs to be
> > > considered? Otherwise technically 6 pairs are possible.
> >
> > An implementation that tries all 6 pairs taking the zpos and the
> > overlapping into account is appreciated. I cared for the simplest case
> > here. Yes, further optimizations can be implemented.
> >
>
> Ok got it. So you would like to build a better one on top of this.
> But I see one case where this has an issue or is not optimal. Pls see below.
Yes, it is not optimal. This is the 'best possible effort' or 'best
simple effort' from my POV.
>
> > >
> > >
> > > General request:
> > >
> > > Patches 1-9 : Add support for using 2 SSPPs in one plane
> > > Patches 10-12 : Add support for using two rectangles of the same SSPP as
> > > two virtual planes
> > > Patch 13 : Can be pushed along with the first set.
> > >
> > > Can we break up this series in this way to make it easier to test and
> > > land the bulk of it in this cycle?
> >
> > Sure.
> >
>
> Thanks.
>
> > >
> > > I have some doubts on patches 10-12 and would like to spend more time
> > > reviewing and testing this. So I am trying to reduce the debt of patches
> > > we have been carrying as this is a tricky feature to simulate and test
> > > the cases.
> > >
> > > > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > ---
> > > > drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 128 +++++++++++++++++++---
> > > > 1 file changed, 112 insertions(+), 16 deletions(-)
> > > >
> > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > index cde20c1fa90d..2e1c544efc4a 100644
> > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > @@ -886,10 +886,9 @@ static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
> > > > return 0;
> > > > }
> > > >
> > > > -static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
> > > > - struct dpu_sw_pipe_cfg *pipe_cfg,
> > > > - const struct dpu_format *fmt,
> > > > - uint32_t max_linewidth)
> > > > +static int dpu_plane_is_multirect_capable(struct dpu_sw_pipe *pipe,
> > > > + struct dpu_sw_pipe_cfg *pipe_cfg,
> > > > + const struct dpu_format *fmt)
> > > > {
> > > > 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))
> > > > @@ -901,6 +900,13 @@ static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
> > > > if (DPU_FORMAT_IS_YUV(fmt))
> > > > return false;
> > > >
> > > > + return true;
> > > > +}
> > > > +
> > > > +static int dpu_plane_is_parallel_capable(struct dpu_sw_pipe_cfg *pipe_cfg,
> > > > + const struct dpu_format *fmt,
> > > > + uint32_t max_linewidth)
> > > > +{
> > > > if (DPU_FORMAT_IS_UBWC(fmt) &&
> > > > drm_rect_width(&pipe_cfg->src_rect) > max_linewidth / 2)
> > > > return false;
> > > > @@ -908,6 +914,82 @@ static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
> > > > return true;
> > > > }
> > > >
> > > > +static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
> > > > + struct dpu_sw_pipe_cfg *pipe_cfg,
> > > > + const struct dpu_format *fmt,
> > > > + uint32_t max_linewidth)
> > > > +{
> > > > + return dpu_plane_is_multirect_capable(pipe, pipe_cfg, fmt) &&
> > > > + dpu_plane_is_parallel_capable(pipe_cfg, fmt, max_linewidth);
> > > > +}
> > > > +
> > > > +
> > > > +static int dpu_plane_try_multirect(struct dpu_plane_state *pstate,
> > > > + struct dpu_plane_state *prev_pstate,
> > > > + const struct dpu_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_pstate->pipe;
> > > > + struct dpu_sw_pipe_cfg *prev_pipe_cfg = &prev_pstate->pipe_cfg;
> > > > + const struct dpu_format *prev_fmt =
> > > > + to_dpu_format(msm_framebuffer_format(prev_pstate->base.fb));
> > > > + u16 max_tile_height = 1;
> > > > +
> > > > + if (prev_pstate->r_pipe.sspp != NULL ||
> > > > + prev_pipe->multirect_mode != DPU_SSPP_MULTIRECT_NONE)
> > > > + return false;
> > > > +
> > > > + if (!dpu_plane_is_multirect_capable(pipe, pipe_cfg, fmt) ||
> > > > + !dpu_plane_is_multirect_capable(prev_pipe, prev_pipe_cfg, prev_fmt) ||
> > > > + !(test_bit(DPU_SSPP_SMART_DMA_V1, &prev_pipe->sspp->cap->features) ||
> > > > + test_bit(DPU_SSPP_SMART_DMA_V2, &prev_pipe->sspp->cap->features)))
> > >
> > > This test_bit check should be absorbed into
> > > dpu_plane_is_multirect_capable()?
> >
> > Yep.
> >
> > >
> > > > + return false;
> > > > +
> > > > + if (DPU_FORMAT_IS_UBWC(fmt))
> > > > + max_tile_height = max(max_tile_height, fmt->tile_height);
> > > > +
> > > > + if (DPU_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 ||
> > > > + prev_pipe_cfg->dst_rect.x1 >= pipe_cfg->dst_rect.x2)) {
> > >
> > > Even if y1 > y2 or y2 > y1 but the separation is less than the 2 *
> > > max_tile_height, it can qualify for parallel fetch.
> > >
> > > So parallel fetch is possible not only in x direction but y direction as
> > > well as it will be fetched by different SSPPs.
> >
> > I think that's now what I see in the SDE driver.
> >
>
> hmm , okay, we can support that case once this one works without issues.
>
> > >
> > > > + pipe->sspp = prev_pipe->sspp;
> > > > +
> > > > + pipe->multirect_index = DPU_SSPP_RECT_1;
> > > > + pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
> > > > +
> > > > + prev_pipe->multirect_index = DPU_SSPP_RECT_0;
> > > > + prev_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
> > > > +
> > > > + return true;
> > > > + }
> > > > +
> > > > + if (pipe_cfg->dst_rect.y1 >= prev_pipe_cfg->dst_rect.y2 + 2 * max_tile_height ||
> > > > + prev_pipe_cfg->dst_rect.y1 >= pipe_cfg->dst_rect.y2 + 2 * max_tile_height) {
> > > > + pipe->sspp = prev_pipe->sspp;
> > > > +
> > > > + pipe->multirect_index = DPU_SSPP_RECT_1;
> > > > + pipe->multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX;
> > > > +
> > > > + prev_pipe->multirect_index = DPU_SSPP_RECT_0;
> > > > + prev_pipe->multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX;
> > > > +
> > > > + return true;
> > > > + }
> > > > +
> > > > + return false;
> > > > +}
> > > > +
> > > > static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
> > > > struct drm_atomic_state *state,
> > > > const struct drm_crtc_state *crtc_state)
> > > > @@ -1098,13 +1180,14 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
> > > > 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 *plane_state,
> > > > + struct drm_plane_state *prev_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;
> > > > + struct dpu_plane_state *pstate, *prev_pstate;
> > > > struct dpu_sw_pipe *pipe;
> > > > struct dpu_sw_pipe *r_pipe;
> > > > struct dpu_sw_pipe_cfg *pipe_cfg;
> > > > @@ -1117,6 +1200,7 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
> > > > plane_state->crtc);
> > > >
> > > > pstate = to_dpu_plane_state(plane_state);
> > > > + prev_pstate = prev_plane_state ? to_dpu_plane_state(prev_plane_state) : NULL;
> > > > pipe = &pstate->pipe;
> > > > r_pipe = &pstate->r_pipe;
> > > > pipe_cfg = &pstate->pipe_cfg;
> > > > @@ -1137,19 +1221,27 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
> > > >
> > > > max_linewidth = dpu_kms->catalog->caps->max_linewidth;
> > > >
> > > > - pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
> > > > - if (!pipe->sspp)
> > > > - return -ENODEV;
> > > > -
> > > > if (drm_rect_width(&r_pipe_cfg->src_rect) == 0) {
> > > > - pipe->multirect_index = DPU_SSPP_RECT_SOLO;
> > > > - pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
> > > > + if (!prev_pstate ||
> > > > + !dpu_plane_try_multirect(pstate, prev_pstate, fmt, max_linewidth)) {
> > >
> > > This is a bit confusing to check esp since i am unable to apply this
> > > patch and check .... but...
> >
> > It was posted several months ago. No surprise that the source code has
> > evolved. Getting the patches reviewed in time would have helped them
> > to be applicable.
> >
>
> Yes, part of the delays for virtual plane was purely because the CB setup
> was down (both due to internal IT issues and general sc7280 being down) and
> I want to make sure this series is compositor-tested and not just modetest
> tested.
>
> But anyway, thats why I didnt request a rebase this time even though it was
> very hard to review the patch emails for this series.
Review is review, testing is testing. Those are two different items.
It's perfectly fine to review a patchset and at the same time to add a
notice 'don't merge until fully validated on a hardware'.
>
> > > dpu_plane_atomic_check_nopipe() will set r_pipe_cfg if we are going to
> > > do multirect with two rectangles of the same sspp. Right?
> >
> > No. It sets r_pipe_cfg in all the cases.
> >
>
> From what I see, we still have this check before a valid rectangle is set
> for the r_pipe_cfg
>
> if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) ||
> _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) >
> max_mdp_clk_rate) {
I really don't see a contradiction here. Maybe I'm missing something.
> > > Which means r_pipe_cfg will be 0 if multirect is not possible with same
> > > SSPP. Thats why the else case of this either uses two SSPPs.
> >
> > No. It means that the plane can use a single rectangle of the SSPP.
> >
>
> OR that the plane does not need to use multirect because its rectangle width
> is < max_linewidth.
Isn't it the same fact, just expressed in different words?
>
> > >
> > > So why are we trying multirect with again with the two rectangles of the
> > > same SSPP as different planes? The result will be same right?
> >
> > No, if the width of r_pipe_cfg is 0, it means that this plane doesn't
> > need a second rectangle to be displayed. So we can try reusing the
> > SSPP from the previous plane.
> >
>
> Yes, agreed to this point that this plane doesnt need a second rectangle to
> be displayed as it will fit in one rectangle.
>
> And I see what you mean now, if the current plane needs only one rectangle
> to be used, you are trying to use the prev plane's SSPP's other rect?
>
> So lets say we have plane 1 and plane 2 in the list.
>
> Plane 1 has only one rect used and plane 2 also needs only one rect.
>
> Then you use plane 1's SSPP even for plane 2.
Yes!
> Cant you use an alternative check like !dpu_plane_is_wideplane_multirect()
> to make this condition clear?
No. There might be other conditions in play. So we really need to check
both pipe configurations together in order to determine.
> Also dpu_plane_try_multirect() name is confusing then because you are trying
> multi-rect again to see if the SSPP can be shared and wide-plane multirect
> was not possible. So technically both are multirect, just dfferent
> applications.
dpu_plane_try_sharing_sspp() ?
> That will make it clear that you are trying to use multi-rect for sharing
> SSPP.
>
> So there are essentially two use-cases of multi-rect:
>
> 1) Wide plane multi-rect
> 2) SSPP sharing multi-rect
>
> So this will make it clear.
Ideally we should be able to get rid of this distinction. Maybe in the
end we should just list all pipe configurations in some natural order
and then assign SSPP rectangles.
>
> Coming to the algorithm, I see one issue with this now.
>
> Lets say we have this list of SSPPs.
>
> DMA0 Vig0 Vig1
Fine.
>
> DMA0 has only rec0 used and rec1 is free.
>
> Vig0 needs both recs used.
>
> Vig1 needs only one rec.
And this is not fine. There are no fixed planes like DMA0, etc.
Let me rephrase that for you, if I got your example correctly. We have
three planes, first one is small RGB plane, so it requires only a single
rectangle, second plane requires both rectangles of VIG0.
Third plane could have fit into DMA1 / REC1, but using this algorithm we
end up allocating VIG1 for the third plane.
> Here it will notice that its previous plane has both rects used and will not
> try the DMA0 even though it has one rect free and will end up using a new
> SSPP.
>
> Thats why considering only immediate pairs is not enough. All possible pairs
> will address this.
Yes, I know the algorithm is not optimal from the resource management
point of view. However:
- I was not sure how allocating two rectangles of the same SSPP for
different stages will work across different hardware generations, etc.
This algorithm doesn't have such an issue, because both rectangles are
always using the same blending stage.
- Trying all possible combinations requires exponential time for the
number of planes in use. The simple algorithm works in a linear time,
while being good enough for the simplest cases.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 10/13] drm/msm/dpu: allow sharing SSPP between planes
2024-06-13 10:05 ` Dmitry Baryshkov
@ 2024-06-13 20:02 ` Abhinav Kumar
0 siblings, 0 replies; 50+ messages in thread
From: Abhinav Kumar @ 2024-06-13 20:02 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On 6/13/2024 3:05 AM, Dmitry Baryshkov wrote:
> On Wed, Jun 12, 2024 at 06:17:37PM -0700, Abhinav Kumar wrote:
>>
>>
>> On 6/12/2024 2:08 AM, Dmitry Baryshkov wrote:
>>> On Wed, 12 Jun 2024 at 02:12, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>>>>
>>>>
>>>>
>>>> On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
>>>>> Since SmartDMA planes provide two rectangles, it is possible to use them
>>>>> to drive two different DRM planes, first plane getting the rect_0,
>>>>> another one using rect_1 of the same SSPP. The sharing algorithm is
>>>>> pretty simple, it requires that each of the planes can be driven by the
>>>>> single rectangle and only consequetive planes are considered.
>>>>>
>>>>
>>>> consequetive - > consecutive
>>>>
>>>> Can you please explain why only consecutive planes are considered for this?
>>>>
>>>> So lets say we have 4 virtual planes : 0, 1, 2, 3
>>>>
>>>> It will try 0-1, 1-2, 2-3
>>>>
>>>> Because all planes are virtual, there are only 3 unique pairs to be
>>>> considered? Otherwise technically 6 pairs are possible.
>>>
>>> An implementation that tries all 6 pairs taking the zpos and the
>>> overlapping into account is appreciated. I cared for the simplest case
>>> here. Yes, further optimizations can be implemented.
>>>
>>
>> Ok got it. So you would like to build a better one on top of this.
>> But I see one case where this has an issue or is not optimal. Pls see below.
>
> Yes, it is not optimal. This is the 'best possible effort' or 'best
> simple effort' from my POV.
>
>>
>>>>
>>>>
>>>> General request:
>>>>
>>>> Patches 1-9 : Add support for using 2 SSPPs in one plane
>>>> Patches 10-12 : Add support for using two rectangles of the same SSPP as
>>>> two virtual planes
>>>> Patch 13 : Can be pushed along with the first set.
>>>>
>>>> Can we break up this series in this way to make it easier to test and
>>>> land the bulk of it in this cycle?
>>>
>>> Sure.
>>>
>>
>> Thanks.
>>
>>>>
>>>> I have some doubts on patches 10-12 and would like to spend more time
>>>> reviewing and testing this. So I am trying to reduce the debt of patches
>>>> we have been carrying as this is a tricky feature to simulate and test
>>>> the cases.
>>>>
>>>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>>>> ---
>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 128 +++++++++++++++++++---
>>>>> 1 file changed, 112 insertions(+), 16 deletions(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>>>> index cde20c1fa90d..2e1c544efc4a 100644
>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>>>> @@ -886,10 +886,9 @@ static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
>>>>> return 0;
>>>>> }
>>>>>
>>>>> -static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
>>>>> - struct dpu_sw_pipe_cfg *pipe_cfg,
>>>>> - const struct dpu_format *fmt,
>>>>> - uint32_t max_linewidth)
>>>>> +static int dpu_plane_is_multirect_capable(struct dpu_sw_pipe *pipe,
>>>>> + struct dpu_sw_pipe_cfg *pipe_cfg,
>>>>> + const struct dpu_format *fmt)
>>>>> {
>>>>> 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))
>>>>> @@ -901,6 +900,13 @@ static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
>>>>> if (DPU_FORMAT_IS_YUV(fmt))
>>>>> return false;
>>>>>
>>>>> + return true;
>>>>> +}
>>>>> +
>>>>> +static int dpu_plane_is_parallel_capable(struct dpu_sw_pipe_cfg *pipe_cfg,
>>>>> + const struct dpu_format *fmt,
>>>>> + uint32_t max_linewidth)
>>>>> +{
>>>>> if (DPU_FORMAT_IS_UBWC(fmt) &&
>>>>> drm_rect_width(&pipe_cfg->src_rect) > max_linewidth / 2)
>>>>> return false;
>>>>> @@ -908,6 +914,82 @@ static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
>>>>> return true;
>>>>> }
>>>>>
>>>>> +static int dpu_plane_is_multirect_parallel_capable(struct dpu_sw_pipe *pipe,
>>>>> + struct dpu_sw_pipe_cfg *pipe_cfg,
>>>>> + const struct dpu_format *fmt,
>>>>> + uint32_t max_linewidth)
>>>>> +{
>>>>> + return dpu_plane_is_multirect_capable(pipe, pipe_cfg, fmt) &&
>>>>> + dpu_plane_is_parallel_capable(pipe_cfg, fmt, max_linewidth);
>>>>> +}
>>>>> +
>>>>> +
>>>>> +static int dpu_plane_try_multirect(struct dpu_plane_state *pstate,
>>>>> + struct dpu_plane_state *prev_pstate,
>>>>> + const struct dpu_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_pstate->pipe;
>>>>> + struct dpu_sw_pipe_cfg *prev_pipe_cfg = &prev_pstate->pipe_cfg;
>>>>> + const struct dpu_format *prev_fmt =
>>>>> + to_dpu_format(msm_framebuffer_format(prev_pstate->base.fb));
>>>>> + u16 max_tile_height = 1;
>>>>> +
>>>>> + if (prev_pstate->r_pipe.sspp != NULL ||
>>>>> + prev_pipe->multirect_mode != DPU_SSPP_MULTIRECT_NONE)
>>>>> + return false;
>>>>> +
>>>>> + if (!dpu_plane_is_multirect_capable(pipe, pipe_cfg, fmt) ||
>>>>> + !dpu_plane_is_multirect_capable(prev_pipe, prev_pipe_cfg, prev_fmt) ||
>>>>> + !(test_bit(DPU_SSPP_SMART_DMA_V1, &prev_pipe->sspp->cap->features) ||
>>>>> + test_bit(DPU_SSPP_SMART_DMA_V2, &prev_pipe->sspp->cap->features)))
>>>>
>>>> This test_bit check should be absorbed into
>>>> dpu_plane_is_multirect_capable()?
>>>
>>> Yep.
>>>
>>>>
>>>>> + return false;
>>>>> +
>>>>> + if (DPU_FORMAT_IS_UBWC(fmt))
>>>>> + max_tile_height = max(max_tile_height, fmt->tile_height);
>>>>> +
>>>>> + if (DPU_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 ||
>>>>> + prev_pipe_cfg->dst_rect.x1 >= pipe_cfg->dst_rect.x2)) {
>>>>
>>>> Even if y1 > y2 or y2 > y1 but the separation is less than the 2 *
>>>> max_tile_height, it can qualify for parallel fetch.
>>>>
>>>> So parallel fetch is possible not only in x direction but y direction as
>>>> well as it will be fetched by different SSPPs.
>>>
>>> I think that's now what I see in the SDE driver.
>>>
>>
>> hmm , okay, we can support that case once this one works without issues.
>>
>>>>
>>>>> + pipe->sspp = prev_pipe->sspp;
>>>>> +
>>>>> + pipe->multirect_index = DPU_SSPP_RECT_1;
>>>>> + pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
>>>>> +
>>>>> + prev_pipe->multirect_index = DPU_SSPP_RECT_0;
>>>>> + prev_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
>>>>> +
>>>>> + return true;
>>>>> + }
>>>>> +
>>>>> + if (pipe_cfg->dst_rect.y1 >= prev_pipe_cfg->dst_rect.y2 + 2 * max_tile_height ||
>>>>> + prev_pipe_cfg->dst_rect.y1 >= pipe_cfg->dst_rect.y2 + 2 * max_tile_height) {
>>>>> + pipe->sspp = prev_pipe->sspp;
>>>>> +
>>>>> + pipe->multirect_index = DPU_SSPP_RECT_1;
>>>>> + pipe->multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX;
>>>>> +
>>>>> + prev_pipe->multirect_index = DPU_SSPP_RECT_0;
>>>>> + prev_pipe->multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX;
>>>>> +
>>>>> + return true;
>>>>> + }
>>>>> +
>>>>> + return false;
>>>>> +}
>>>>> +
>>>>> static int dpu_plane_atomic_check_pipes(struct drm_plane *plane,
>>>>> struct drm_atomic_state *state,
>>>>> const struct drm_crtc_state *crtc_state)
>>>>> @@ -1098,13 +1180,14 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
>>>>> 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 *plane_state,
>>>>> + struct drm_plane_state *prev_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;
>>>>> + struct dpu_plane_state *pstate, *prev_pstate;
>>>>> struct dpu_sw_pipe *pipe;
>>>>> struct dpu_sw_pipe *r_pipe;
>>>>> struct dpu_sw_pipe_cfg *pipe_cfg;
>>>>> @@ -1117,6 +1200,7 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
>>>>> plane_state->crtc);
>>>>>
>>>>> pstate = to_dpu_plane_state(plane_state);
>>>>> + prev_pstate = prev_plane_state ? to_dpu_plane_state(prev_plane_state) : NULL;
>>>>> pipe = &pstate->pipe;
>>>>> r_pipe = &pstate->r_pipe;
>>>>> pipe_cfg = &pstate->pipe_cfg;
>>>>> @@ -1137,19 +1221,27 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
>>>>>
>>>>> max_linewidth = dpu_kms->catalog->caps->max_linewidth;
>>>>>
>>>>> - pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs);
>>>>> - if (!pipe->sspp)
>>>>> - return -ENODEV;
>>>>> -
>>>>> if (drm_rect_width(&r_pipe_cfg->src_rect) == 0) {
>>>>> - pipe->multirect_index = DPU_SSPP_RECT_SOLO;
>>>>> - pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
>>>>> + if (!prev_pstate ||
>>>>> + !dpu_plane_try_multirect(pstate, prev_pstate, fmt, max_linewidth)) {
>>>>
>>>> This is a bit confusing to check esp since i am unable to apply this
>>>> patch and check .... but...
>>>
>>> It was posted several months ago. No surprise that the source code has
>>> evolved. Getting the patches reviewed in time would have helped them
>>> to be applicable.
>>>
>>
>> Yes, part of the delays for virtual plane was purely because the CB setup
>> was down (both due to internal IT issues and general sc7280 being down) and
>> I want to make sure this series is compositor-tested and not just modetest
>> tested.
>>
>> But anyway, thats why I didnt request a rebase this time even though it was
>> very hard to review the patch emails for this series.
>
> Review is review, testing is testing. Those are two different items.
> It's perfectly fine to review a patchset and at the same time to add a
> notice 'don't merge until fully validated on a hardware'.
>
Ack, I will use this notice from now on.
>>
>>>> dpu_plane_atomic_check_nopipe() will set r_pipe_cfg if we are going to
>>>> do multirect with two rectangles of the same sspp. Right?
>>>
>>> No. It sets r_pipe_cfg in all the cases.
>>>
>>
>> From what I see, we still have this check before a valid rectangle is set
>> for the r_pipe_cfg
>>
>> if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) ||
>> _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) >
>> max_mdp_clk_rate) {
>
> I really don't see a contradiction here. Maybe I'm missing something.
>
>>>> Which means r_pipe_cfg will be 0 if multirect is not possible with same
>>>> SSPP. Thats why the else case of this either uses two SSPPs.
>>>
>>> No. It means that the plane can use a single rectangle of the SSPP.
>>>
>>
>> OR that the plane does not need to use multirect because its rectangle width
>> is < max_linewidth.
>
> Isn't it the same fact, just expressed in different words?
>
>>
>>>>
>>>> So why are we trying multirect with again with the two rectangles of the
>>>> same SSPP as different planes? The result will be same right?
>>>
>>> No, if the width of r_pipe_cfg is 0, it means that this plane doesn't
>>> need a second rectangle to be displayed. So we can try reusing the
>>> SSPP from the previous plane.
>>>
>>
>> Yes, agreed to this point that this plane doesnt need a second rectangle to
>> be displayed as it will fit in one rectangle.
>>
>> And I see what you mean now, if the current plane needs only one rectangle
>> to be used, you are trying to use the prev plane's SSPP's other rect?
>>
>> So lets say we have plane 1 and plane 2 in the list.
>>
>> Plane 1 has only one rect used and plane 2 also needs only one rect.
>>
>> Then you use plane 1's SSPP even for plane 2.
>
> Yes!
>
>> Cant you use an alternative check like !dpu_plane_is_wideplane_multirect()
>> to make this condition clear?
>
> No. There might be other conditions in play. So we really need to check
> both pipe configurations together in order to determine.
>
What I meant was instead of doing !r_pip_cfg->rect maybe put that in a
helper API like dpu_plane_is_wideplane_multirect().
It seems like to me the ideal way would have been that you have both the
checks in the same place rather than breaking it up into a different API
(check_no_pipe)
That way we could have done:
1) Try wide plane multirect
2) if that does not qualify, try SSPP sharing multirect
3) if both do not work, try dual SSPP
Now, it seems like to me that perhaps the migration of setting the
r_pipe_cfg rect inside check_no_pipe() could have been avoided and
rather just kept that outside?
>> Also dpu_plane_try_multirect() name is confusing then because you are trying
>> multi-rect again to see if the SSPP can be shared and wide-plane multirect
>> was not possible. So technically both are multirect, just dfferent
>> applications.
>
> dpu_plane_try_sharing_sspp() ?
>
Yes, this one is better.
>> That will make it clear that you are trying to use multi-rect for sharing
>> SSPP.
>>
>> So there are essentially two use-cases of multi-rect:
>>
>> 1) Wide plane multi-rect
>> 2) SSPP sharing multi-rect
>>
>> So this will make it clear.
>
> Ideally we should be able to get rid of this distinction. Maybe in the
> end we should just list all pipe configurations in some natural order
> and then assign SSPP rectangles.
>
>>
>> Coming to the algorithm, I see one issue with this now.
>>
>> Lets say we have this list of SSPPs.
>>
>> DMA0 Vig0 Vig1
>
> Fine.
>
>>
>> DMA0 has only rec0 used and rec1 is free.
>>
>> Vig0 needs both recs used.
>>
>> Vig1 needs only one rec.
>
> And this is not fine. There are no fixed planes like DMA0, etc.
>
> Let me rephrase that for you, if I got your example correctly. We have
> three planes, first one is small RGB plane, so it requires only a single
> rectangle, second plane requires both rectangles of VIG0.
> Third plane could have fit into DMA1 / REC1, but using this algorithm we
> end up allocating VIG1 for the third plane.
>
Correct, this is the scenario I was trying to explain.
>
>> Here it will notice that its previous plane has both rects used and will not
>> try the DMA0 even though it has one rect free and will end up using a new
>> SSPP.
>>
>> Thats why considering only immediate pairs is not enough. All possible pairs
>> will address this.
>
> Yes, I know the algorithm is not optimal from the resource management
> point of view. However:
>
> - I was not sure how allocating two rectangles of the same SSPP for
> different stages will work across different hardware generations, etc.
> This algorithm doesn't have such an issue, because both rectangles are
> always using the same blending stage.
>
hmm, I am not aware of any restrictions with this regard.
> - Trying all possible combinations requires exponential time for the
> number of planes in use. The simple algorithm works in a linear time,
> while being good enough for the simplest cases.
>
Okay, lets go ahead with this algorithm but I will try to improve this.
>
^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v4 11/13] drm/msm/dpu: create additional virtual planes
2024-03-14 0:02 [PATCH v4 00/13] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
` (9 preceding siblings ...)
2024-03-14 0:02 ` [PATCH v4 10/13] drm/msm/dpu: allow sharing SSPP between planes Dmitry Baryshkov
@ 2024-03-14 0:02 ` Dmitry Baryshkov
2024-06-11 23:26 ` Abhinav Kumar
2024-03-14 0:02 ` [PATCH v4 12/13] drm/msm/dpu: allow sharing of blending stages Dmitry Baryshkov
` (2 subsequent siblings)
13 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-03-14 0:02 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Abhinav Kumar, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
Since we have enabled sharing of SSPP blocks between two planes, it is
now possible to use twice as much planes as there are hardware SSPP
blocks. Create additional overlay planes.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index becdd98f3c40..feb4d3bae0cf 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -790,6 +790,18 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms)
primary_planes[primary_planes_idx++] = plane;
}
+ if (dpu_use_virtual_planes) {
+ for (i = 0; i < catalog->sspp_count; i++) {
+ plane = dpu_plane_init_virtual(dev, DRM_PLANE_TYPE_OVERLAY,
+ (1UL << max_crtc_count) - 1);
+ if (IS_ERR(plane)) {
+ DPU_ERROR("dpu_plane_init failed\n");
+ ret = PTR_ERR(plane);
+ return ret;
+ }
+ }
+ }
+
max_crtc_count = min(max_crtc_count, primary_planes_idx);
/* Create one CRTC per encoder */
--
2.39.2
^ permalink raw reply related [flat|nested] 50+ messages in thread* Re: [PATCH v4 11/13] drm/msm/dpu: create additional virtual planes
2024-03-14 0:02 ` [PATCH v4 11/13] drm/msm/dpu: create additional virtual planes Dmitry Baryshkov
@ 2024-06-11 23:26 ` Abhinav Kumar
0 siblings, 0 replies; 50+ messages in thread
From: Abhinav Kumar @ 2024-06-11 23:26 UTC (permalink / raw)
To: Dmitry Baryshkov, Rob Clark, Sean Paul, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> Since we have enabled sharing of SSPP blocks between two planes, it is
> now possible to use twice as much planes as there are hardware SSPP
> blocks. Create additional overlay planes.
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v4 12/13] drm/msm/dpu: allow sharing of blending stages
2024-03-14 0:02 [PATCH v4 00/13] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
` (10 preceding siblings ...)
2024-03-14 0:02 ` [PATCH v4 11/13] drm/msm/dpu: create additional virtual planes Dmitry Baryshkov
@ 2024-03-14 0:02 ` Dmitry Baryshkov
2024-06-12 1:47 ` Abhinav Kumar
2024-03-14 0:02 ` [PATCH v4 13/13] drm/msm/dpu: include SSPP allocation state into the dumped state Dmitry Baryshkov
2024-03-14 0:04 ` [PATCH v4 00/13] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
13 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-03-14 0:02 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Abhinav Kumar, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
It is possible to slightly bend the limitations of the HW blender. If
two rectangles are contiguous (like two rectangles of a single plane)
they can be blended using a single LM blending stage, allowing one to
blend more planes via a single LM.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 9 ++++--
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 37 ++++++++++++++++++-----
2 files changed, 37 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 794c5643584f..fbbd7f635d04 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -445,6 +445,7 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
uint32_t lm_idx;
bool bg_alpha_enable = false;
+ unsigned int stage_indices[DPU_STAGE_MAX] = {};
DECLARE_BITMAP(fetch_active, SSPP_MAX);
memset(fetch_active, 0, sizeof(fetch_active));
@@ -469,7 +470,9 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
mixer, cstate->num_mixers,
pstate->stage,
format, fb ? fb->modifier : 0,
- &pstate->pipe, 0, stage_cfg);
+ &pstate->pipe,
+ stage_indices[pstate->stage]++,
+ stage_cfg);
if (pstate->r_pipe.sspp) {
set_bit(pstate->r_pipe.sspp->idx, fetch_active);
@@ -477,7 +480,9 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
mixer, cstate->num_mixers,
pstate->stage,
format, fb ? fb->modifier : 0,
- &pstate->r_pipe, 1, stage_cfg);
+ &pstate->r_pipe,
+ stage_indices[pstate->stage]++,
+ stage_cfg);
}
/* blend config update */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index 2e1c544efc4a..43dfe13eb298 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -827,13 +827,6 @@ static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
if (!new_plane_state->visible)
return 0;
- pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos;
- if (pstate->stage >= pdpu->catalog->caps->max_mixer_blendstages) {
- DPU_ERROR("> %d plane stages assigned\n",
- pdpu->catalog->caps->max_mixer_blendstages - DPU_STAGE_0);
- return -EINVAL;
- }
-
/* state->src is 16.16, src_rect is not */
drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src);
@@ -971,6 +964,18 @@ static int dpu_plane_try_multirect(struct dpu_plane_state *pstate,
prev_pipe->multirect_index = DPU_SSPP_RECT_0;
prev_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
+ if (pipe_cfg->dst_rect.y1 == prev_pipe_cfg->dst_rect.y1 &&
+ pipe_cfg->dst_rect.y2 == prev_pipe_cfg->dst_rect.y2 &&
+ pipe_cfg->dst_rect.x1 == prev_pipe_cfg->dst_rect.x2) {
+ pstate->stage = prev_pstate->stage;
+ } else if (pipe_cfg->dst_rect.y1 == prev_pipe_cfg->dst_rect.y1 &&
+ pipe_cfg->dst_rect.y2 == prev_pipe_cfg->dst_rect.y2 &&
+ pipe_cfg->dst_rect.x2 == prev_pipe_cfg->dst_rect.x1) {
+ pstate->stage = prev_pstate->stage;
+ pipe->multirect_index = DPU_SSPP_RECT_0;
+ prev_pipe->multirect_index = DPU_SSPP_RECT_1;
+ }
+
return true;
}
@@ -1080,6 +1085,13 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
if (!new_plane_state->visible)
return 0;
+ pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos;
+ if (pstate->stage >= pdpu->catalog->caps->max_mixer_blendstages) {
+ DPU_ERROR("> %d plane stages assigned\n",
+ pdpu->catalog->caps->max_mixer_blendstages - DPU_STAGE_0);
+ return -EINVAL;
+ }
+
pipe->multirect_index = DPU_SSPP_RECT_SOLO;
pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
r_pipe->multirect_index = DPU_SSPP_RECT_SOLO;
@@ -1221,6 +1233,11 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
max_linewidth = dpu_kms->catalog->caps->max_linewidth;
+ if (prev_pstate)
+ pstate->stage = prev_pstate->stage + 1;
+ else
+ pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos;
+
if (drm_rect_width(&r_pipe_cfg->src_rect) == 0) {
if (!prev_pstate ||
!dpu_plane_try_multirect(pstate, prev_pstate, fmt, max_linewidth)) {
@@ -1267,6 +1284,12 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
}
}
+ if (pstate->stage >= dpu_kms->catalog->caps->max_mixer_blendstages) {
+ DPU_ERROR("> %d plane stages assigned\n",
+ dpu_kms->catalog->caps->max_mixer_blendstages - DPU_STAGE_0);
+ return -EINVAL;
+ }
+
return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
}
--
2.39.2
^ permalink raw reply related [flat|nested] 50+ messages in thread* Re: [PATCH v4 12/13] drm/msm/dpu: allow sharing of blending stages
2024-03-14 0:02 ` [PATCH v4 12/13] drm/msm/dpu: allow sharing of blending stages Dmitry Baryshkov
@ 2024-06-12 1:47 ` Abhinav Kumar
2024-06-12 8:50 ` Dmitry Baryshkov
0 siblings, 1 reply; 50+ messages in thread
From: Abhinav Kumar @ 2024-06-12 1:47 UTC (permalink / raw)
To: Dmitry Baryshkov, Rob Clark, Sean Paul, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> It is possible to slightly bend the limitations of the HW blender. If
> two rectangles are contiguous (like two rectangles of a single plane)
> they can be blended using a single LM blending stage, allowing one to
> blend more planes via a single LM.
>
Can you pls let me know the source of this optimization (assuming its
present downstream) ?
Otherwise I will have to lookup some more docs to confirm this.
It certainly makes sense, that if the same layer is being split across
two SSPP's we can certainly use the same blend stage. But want to make
sure this is already in place somewhere and not something which was
tried and just worked.
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
> drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 9 ++++--
> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 37 ++++++++++++++++++-----
> 2 files changed, 37 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> index 794c5643584f..fbbd7f635d04 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> @@ -445,6 +445,7 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
>
> uint32_t lm_idx;
> bool bg_alpha_enable = false;
> + unsigned int stage_indices[DPU_STAGE_MAX] = {};
> DECLARE_BITMAP(fetch_active, SSPP_MAX);
>
> memset(fetch_active, 0, sizeof(fetch_active));
> @@ -469,7 +470,9 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
> mixer, cstate->num_mixers,
> pstate->stage,
> format, fb ? fb->modifier : 0,
> - &pstate->pipe, 0, stage_cfg);
> + &pstate->pipe,
> + stage_indices[pstate->stage]++,
> + stage_cfg);
>
> if (pstate->r_pipe.sspp) {
> set_bit(pstate->r_pipe.sspp->idx, fetch_active);
> @@ -477,7 +480,9 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
> mixer, cstate->num_mixers,
> pstate->stage,
> format, fb ? fb->modifier : 0,
> - &pstate->r_pipe, 1, stage_cfg);
> + &pstate->r_pipe,
> + stage_indices[pstate->stage]++,
> + stage_cfg);
> }
Is this part of the change related to this patch? We moved from
hard-coding 0 and 1 for the stage_idx to stage_indices[pstate->stage]
will still result in the same values of 0 and 1 right?
The sharing will be achieved with the change below of doing
pstate->stage = prev_pstate->stage.
Rest of the change LGTM.
>
> /* blend config update */
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> index 2e1c544efc4a..43dfe13eb298 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> @@ -827,13 +827,6 @@ static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
> if (!new_plane_state->visible)
> return 0;
>
> - pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos;
> - if (pstate->stage >= pdpu->catalog->caps->max_mixer_blendstages) {
> - DPU_ERROR("> %d plane stages assigned\n",
> - pdpu->catalog->caps->max_mixer_blendstages - DPU_STAGE_0);
> - return -EINVAL;
> - }
> -
> /* state->src is 16.16, src_rect is not */
> drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src);
>
> @@ -971,6 +964,18 @@ static int dpu_plane_try_multirect(struct dpu_plane_state *pstate,
> prev_pipe->multirect_index = DPU_SSPP_RECT_0;
> prev_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
>
> + if (pipe_cfg->dst_rect.y1 == prev_pipe_cfg->dst_rect.y1 &&
> + pipe_cfg->dst_rect.y2 == prev_pipe_cfg->dst_rect.y2 &&
> + pipe_cfg->dst_rect.x1 == prev_pipe_cfg->dst_rect.x2) {
> + pstate->stage = prev_pstate->stage;
> + } else if (pipe_cfg->dst_rect.y1 == prev_pipe_cfg->dst_rect.y1 &&
> + pipe_cfg->dst_rect.y2 == prev_pipe_cfg->dst_rect.y2 &&
> + pipe_cfg->dst_rect.x2 == prev_pipe_cfg->dst_rect.x1) {
> + pstate->stage = prev_pstate->stage;
> + pipe->multirect_index = DPU_SSPP_RECT_0;
> + prev_pipe->multirect_index = DPU_SSPP_RECT_1;
> + }
> +
> return true;
> }
>
> @@ -1080,6 +1085,13 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> if (!new_plane_state->visible)
> return 0;
>
> + pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos;
> + if (pstate->stage >= pdpu->catalog->caps->max_mixer_blendstages) {
> + DPU_ERROR("> %d plane stages assigned\n",
> + pdpu->catalog->caps->max_mixer_blendstages - DPU_STAGE_0);
> + return -EINVAL;
> + }
> +
> pipe->multirect_index = DPU_SSPP_RECT_SOLO;
> pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
> r_pipe->multirect_index = DPU_SSPP_RECT_SOLO;
> @@ -1221,6 +1233,11 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
>
> max_linewidth = dpu_kms->catalog->caps->max_linewidth;
>
> + if (prev_pstate)
> + pstate->stage = prev_pstate->stage + 1;
> + else
> + pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos;
> +
> if (drm_rect_width(&r_pipe_cfg->src_rect) == 0) {
> if (!prev_pstate ||
> !dpu_plane_try_multirect(pstate, prev_pstate, fmt, max_linewidth)) {
> @@ -1267,6 +1284,12 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
> }
> }
>
> + if (pstate->stage >= dpu_kms->catalog->caps->max_mixer_blendstages) {
> + DPU_ERROR("> %d plane stages assigned\n",
> + dpu_kms->catalog->caps->max_mixer_blendstages - DPU_STAGE_0);
> + return -EINVAL;
> + }
> +
> return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
> }
>
^ permalink raw reply [flat|nested] 50+ messages in thread* Re: [PATCH v4 12/13] drm/msm/dpu: allow sharing of blending stages
2024-06-12 1:47 ` Abhinav Kumar
@ 2024-06-12 8:50 ` Dmitry Baryshkov
0 siblings, 0 replies; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-06-12 8:50 UTC (permalink / raw)
To: Abhinav Kumar
Cc: Rob Clark, Sean Paul, Marijn Suijten, Stephen Boyd, David Airlie,
Daniel Vetter, Bjorn Andersson, linux-arm-msm, dri-devel,
freedreno
On Wed, 12 Jun 2024 at 04:48, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>
>
>
> On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> > It is possible to slightly bend the limitations of the HW blender. If
> > two rectangles are contiguous (like two rectangles of a single plane)
> > they can be blended using a single LM blending stage, allowing one to
> > blend more planes via a single LM.
> >
>
> Can you pls let me know the source of this optimization (assuming its
> present downstream) ?
>
> Otherwise I will have to lookup some more docs to confirm this.
>
> It certainly makes sense, that if the same layer is being split across
> two SSPP's we can certainly use the same blend stage. But want to make
> sure this is already in place somewhere and not something which was
> tried and just worked.
My source was the original 'virtual' / 'multirect' implementation in
the SDE driver.
>
>
> > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > ---
> > drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 9 ++++--
> > drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 37 ++++++++++++++++++-----
> > 2 files changed, 37 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > index 794c5643584f..fbbd7f635d04 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > @@ -445,6 +445,7 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
> >
> > uint32_t lm_idx;
> > bool bg_alpha_enable = false;
> > + unsigned int stage_indices[DPU_STAGE_MAX] = {};
> > DECLARE_BITMAP(fetch_active, SSPP_MAX);
> >
> > memset(fetch_active, 0, sizeof(fetch_active));
> > @@ -469,7 +470,9 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
> > mixer, cstate->num_mixers,
> > pstate->stage,
> > format, fb ? fb->modifier : 0,
> > - &pstate->pipe, 0, stage_cfg);
> > + &pstate->pipe,
> > + stage_indices[pstate->stage]++,
> > + stage_cfg);
> >
> > if (pstate->r_pipe.sspp) {
> > set_bit(pstate->r_pipe.sspp->idx, fetch_active);
> > @@ -477,7 +480,9 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
> > mixer, cstate->num_mixers,
> > pstate->stage,
> > format, fb ? fb->modifier : 0,
> > - &pstate->r_pipe, 1, stage_cfg);
> > + &pstate->r_pipe,
> > + stage_indices[pstate->stage]++,
> > + stage_cfg);
> > }
>
> Is this part of the change related to this patch? We moved from
> hard-coding 0 and 1 for the stage_idx to stage_indices[pstate->stage]
> will still result in the same values of 0 and 1 right?
No. The stage can span multiple planes now, see one of the chunks below.
>
> The sharing will be achieved with the change below of doing
> pstate->stage = prev_pstate->stage.
>
> Rest of the change LGTM.
>
>
> >
> > /* blend config update */
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > index 2e1c544efc4a..43dfe13eb298 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > @@ -827,13 +827,6 @@ static int dpu_plane_atomic_check_nopipe(struct drm_plane *plane,
> > if (!new_plane_state->visible)
> > return 0;
> >
> > - pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos;
> > - if (pstate->stage >= pdpu->catalog->caps->max_mixer_blendstages) {
> > - DPU_ERROR("> %d plane stages assigned\n",
> > - pdpu->catalog->caps->max_mixer_blendstages - DPU_STAGE_0);
> > - return -EINVAL;
> > - }
> > -
> > /* state->src is 16.16, src_rect is not */
> > drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src);
> >
> > @@ -971,6 +964,18 @@ static int dpu_plane_try_multirect(struct dpu_plane_state *pstate,
> > prev_pipe->multirect_index = DPU_SSPP_RECT_0;
> > prev_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
> >
> > + if (pipe_cfg->dst_rect.y1 == prev_pipe_cfg->dst_rect.y1 &&
> > + pipe_cfg->dst_rect.y2 == prev_pipe_cfg->dst_rect.y2 &&
> > + pipe_cfg->dst_rect.x1 == prev_pipe_cfg->dst_rect.x2) {
> > + pstate->stage = prev_pstate->stage;
> > + } else if (pipe_cfg->dst_rect.y1 == prev_pipe_cfg->dst_rect.y1 &&
> > + pipe_cfg->dst_rect.y2 == prev_pipe_cfg->dst_rect.y2 &&
> > + pipe_cfg->dst_rect.x2 == prev_pipe_cfg->dst_rect.x1) {
> > + pstate->stage = prev_pstate->stage;
> > + pipe->multirect_index = DPU_SSPP_RECT_0;
> > + prev_pipe->multirect_index = DPU_SSPP_RECT_1;
> > + }
> > +
> > return true;
> > }
> >
> > @@ -1080,6 +1085,13 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> > if (!new_plane_state->visible)
> > return 0;
> >
> > + pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos;
> > + if (pstate->stage >= pdpu->catalog->caps->max_mixer_blendstages) {
> > + DPU_ERROR("> %d plane stages assigned\n",
> > + pdpu->catalog->caps->max_mixer_blendstages - DPU_STAGE_0);
> > + return -EINVAL;
> > + }
> > +
> > pipe->multirect_index = DPU_SSPP_RECT_SOLO;
> > pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
> > r_pipe->multirect_index = DPU_SSPP_RECT_SOLO;
> > @@ -1221,6 +1233,11 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
> >
> > max_linewidth = dpu_kms->catalog->caps->max_linewidth;
> >
> > + if (prev_pstate)
> > + pstate->stage = prev_pstate->stage + 1;
> > + else
> > + pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos;
> > +
> > if (drm_rect_width(&r_pipe_cfg->src_rect) == 0) {
> > if (!prev_pstate ||
> > !dpu_plane_try_multirect(pstate, prev_pstate, fmt, max_linewidth)) {
> > @@ -1267,6 +1284,12 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
> > }
> > }
> >
> > + if (pstate->stage >= dpu_kms->catalog->caps->max_mixer_blendstages) {
> > + DPU_ERROR("> %d plane stages assigned\n",
> > + dpu_kms->catalog->caps->max_mixer_blendstages - DPU_STAGE_0);
> > + return -EINVAL;
> > + }
> > +
> > return dpu_plane_atomic_check_pipes(plane, state, crtc_state);
> > }
> >
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v4 13/13] drm/msm/dpu: include SSPP allocation state into the dumped state
2024-03-14 0:02 [PATCH v4 00/13] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
` (11 preceding siblings ...)
2024-03-14 0:02 ` [PATCH v4 12/13] drm/msm/dpu: allow sharing of blending stages Dmitry Baryshkov
@ 2024-03-14 0:02 ` Dmitry Baryshkov
2024-06-11 23:43 ` Abhinav Kumar
2024-03-14 0:04 ` [PATCH v4 00/13] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
13 siblings, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-03-14 0:02 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Abhinav Kumar, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
Make dpu_rm_print_state() also output the SSPP allocation state.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
index 7264a4d44a14..7997df340f72 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
@@ -890,4 +890,11 @@ void dpu_rm_print_state(struct drm_printer *p,
dpu_rm_print_state_helper(p, rm->cdm_blk,
global_state->cdm_to_enc_id);
drm_puts(p, "\n");
+
+ drm_puts(p, "\tsspp=");
+ /* skip SSPP_NONE and start from the next index */
+ for (i = SSPP_NONE + 1; i < ARRAY_SIZE(global_state->sspp_to_crtc_id); i++)
+ dpu_rm_print_state_helper(p, rm->hw_sspp[i] ? &rm->hw_sspp[i]->base : NULL,
+ global_state->sspp_to_crtc_id[i]);
+ drm_puts(p, "\n");
}
--
2.39.2
^ permalink raw reply related [flat|nested] 50+ messages in thread* Re: [PATCH v4 13/13] drm/msm/dpu: include SSPP allocation state into the dumped state
2024-03-14 0:02 ` [PATCH v4 13/13] drm/msm/dpu: include SSPP allocation state into the dumped state Dmitry Baryshkov
@ 2024-06-11 23:43 ` Abhinav Kumar
0 siblings, 0 replies; 50+ messages in thread
From: Abhinav Kumar @ 2024-06-11 23:43 UTC (permalink / raw)
To: Dmitry Baryshkov, Rob Clark, Sean Paul, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> Make dpu_rm_print_state() also output the SSPP allocation state.
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH v4 00/13] drm/msm/dpu: support virtual wide planes
2024-03-14 0:02 [PATCH v4 00/13] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
` (12 preceding siblings ...)
2024-03-14 0:02 ` [PATCH v4 13/13] drm/msm/dpu: include SSPP allocation state into the dumped state Dmitry Baryshkov
@ 2024-03-14 0:04 ` Dmitry Baryshkov
13 siblings, 0 replies; 50+ messages in thread
From: Dmitry Baryshkov @ 2024-03-14 0:04 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Abhinav Kumar, Marijn Suijten
Cc: Stephen Boyd, David Airlie, Daniel Vetter, Bjorn Andersson,
linux-arm-msm, dri-devel, freedreno
On Thu, 14 Mar 2024 at 02:02, Dmitry Baryshkov
<dmitry.baryshkov@linaro.org> wrote:
>
> As promised in the basic wide planes support ([1]) here comes a series
> supporting 2*max_linewidth for all the planes.
>
> Note: Unlike v1 and v2 this series finally includes support for
> additional planes - having more planes than the number of SSPP blocks.
>
> Note: this iteration features handling of rotation and reflection of the
> wide plane. However rot90 is still not tested: it is enabled on sc7280
> and it only supports UBWC (tiled) framebuffers, it was quite low on my
> priority list.
>
> [1] https://patchwork.freedesktop.org/series/99909/
Forgot to mention dependencies, https://patchwork.freedesktop.org/series/130086/
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 50+ messages in thread