* [PATCH v6 0/9] drm/msm/dpu: support virtual wide planes
@ 2024-10-25 0:20 Dmitry Baryshkov
2024-10-25 0:20 ` [PATCH v6 1/9] drm/msm/dpu: use drm_rect_fp_to_int() Dmitry Baryshkov
` (9 more replies)
0 siblings, 10 replies; 30+ messages in thread
From: Dmitry Baryshkov @ 2024-10-25 0:20 UTC (permalink / raw)
To: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten, David Airlie,
Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
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/
---
Changes in v6:
- Renamed dpu_plane_atomic_check_nopipe() ->
dpu_plane_atomic_check_nosspp() and dpu_plane_atomic_check_pipes() ->
dpu_plane_atomic_check_sspp() (Abhinav)
- In dpu_rm_reserve_sspp() replaced hweight usage with explicit type
allocation (Abhinav)
- In dpu_plane_atomic_check() set r_pipe->sspp (Jun Nie)
- In dpu_rm_reserve_sspp() check hw_sspp->ops.setup_scaler to rule out
SSPP blocks with unsupported scaler blocks (RGB, QSEED2)
- Link to v5: https://lore.kernel.org/r/20240627-dpu-virtual-wide-v5-0-5efb90cbb8be@linaro.org
Changes in v5:
- Dropped extra dpu_kms instance from dpu_plane_atomic_check() (Abhinav)
- Use DRM_PLANE_NO_SCALING instead of (1 << 16) (Abhinav)
- Dropped excess returns documentation for dpu_rm_reserve_sspp() (Sui
Jingfeng, Abhinav)
- best_weght -> best_weight (Abhinav)
- Moved drm_rect_width() call back to the the patch "split
dpu_plane_atomic_check()" (Abhinav)
- Got rid of saved_fmt / saved dimensions (Abhinav)
- Expanded the commit message to describe SSPP allocation per CRTC id
(Abhinav)
- Added comment on why the size change also causes resource reallocation
(Abhinav)
- Dropeed several last "feature" patches, leaving only SSPP reallocation
and using 2 SSPPs per plane for now. The rest will be submitted
separately.
Changes since v3:
- Dropped the drm_atomic_helper_check_plane_noscale (Ville)
- Reworked the scaling factor according to global value and then check
if SSPP has scaler_blk later on.
- Split drm_rect_fp_to_int from the rotation-related fix (Abhinav)
Changes since v2:
- Dropped the encoder-related parts, leave all resource allocation as is
(Abhinav)
- Significantly reworked the SSPP allocation code
- Added debugging code to dump RM state in dri/N/state
Changes since v1:
- Fixed build error due to me missing one of fixups, it was left
uncommitted.
- Implementated proper handling of wide plane rotation & reflection.
---
Dmitry Baryshkov (9):
drm/msm/dpu: use drm_rect_fp_to_int()
drm/msm/dpu: move pstate->pipe initialization to dpu_plane_atomic_check
drm/msm/dpu: drop virt_formats from SSPP subblock configuration
drm/msm/dpu: move scaling limitations out of the hw_catalog
drm/msm/dpu: split dpu_plane_atomic_check()
drm/msm/dpu: move rot90 checking to dpu_plane_atomic_check_sspp()
drm/msm/dpu: add support for virtual planes
drm/msm/dpu: allow using two SSPP blocks for a single plane
drm/msm/dpu: include SSPP allocation state into the dumped state
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 50 +++
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 28 --
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 8 -
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h | 2 +
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 | 539 +++++++++++++++++++------
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 18 +-
drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 75 ++++
drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 27 ++
10 files changed, 606 insertions(+), 155 deletions(-)
---
base-commit: 2261751d5f2233a7a5d4791d6d13a0271e838ca5
change-id: 20240626-dpu-virtual-wide-beefb746a900
Best regards,
--
Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v6 1/9] drm/msm/dpu: use drm_rect_fp_to_int()
2024-10-25 0:20 [PATCH v6 0/9] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
@ 2024-10-25 0:20 ` Dmitry Baryshkov
2024-10-25 0:20 ` [PATCH v6 2/9] drm/msm/dpu: move pstate->pipe initialization to dpu_plane_atomic_check Dmitry Baryshkov
` (8 subsequent siblings)
9 siblings, 0 replies; 30+ messages in thread
From: Dmitry Baryshkov @ 2024-10-25 0:20 UTC (permalink / raw)
To: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten, David Airlie,
Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
Use the drm_rect_fp_to_int() helper instead of using the hand-written
code.
Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
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 e935e9c05f04..37faf5b238b0 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -829,13 +829,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.5
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v6 2/9] drm/msm/dpu: move pstate->pipe initialization to dpu_plane_atomic_check
2024-10-25 0:20 [PATCH v6 0/9] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
2024-10-25 0:20 ` [PATCH v6 1/9] drm/msm/dpu: use drm_rect_fp_to_int() Dmitry Baryshkov
@ 2024-10-25 0:20 ` Dmitry Baryshkov
2024-10-25 19:00 ` Abhinav Kumar
2024-10-25 0:20 ` [PATCH v6 3/9] drm/msm/dpu: drop virt_formats from SSPP subblock configuration Dmitry Baryshkov
` (7 subsequent siblings)
9 siblings, 1 reply; 30+ messages in thread
From: Dmitry Baryshkov @ 2024-10-25 0:20 UTC (permalink / raw)
To: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten, David Airlie,
Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
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 | 25 +++++++++++--------------
1 file changed, 11 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 37faf5b238b0..725c9a5826fd 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -797,13 +797,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(&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,
@@ -820,7 +829,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) {
@@ -1286,7 +1294,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");
@@ -1308,16 +1315,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.5
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v6 3/9] drm/msm/dpu: drop virt_formats from SSPP subblock configuration
2024-10-25 0:20 [PATCH v6 0/9] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
2024-10-25 0:20 ` [PATCH v6 1/9] drm/msm/dpu: use drm_rect_fp_to_int() Dmitry Baryshkov
2024-10-25 0:20 ` [PATCH v6 2/9] drm/msm/dpu: move pstate->pipe initialization to dpu_plane_atomic_check Dmitry Baryshkov
@ 2024-10-25 0:20 ` Dmitry Baryshkov
2024-10-25 0:20 ` [PATCH v6 4/9] drm/msm/dpu: move scaling limitations out of the hw_catalog Dmitry Baryshkov
` (6 subsequent siblings)
9 siblings, 0 replies; 30+ messages in thread
From: Dmitry Baryshkov @ 2024-10-25 0:20 UTC (permalink / raw)
To: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten, David Airlie,
Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
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.
Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
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 ----
2 files changed, 16 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 f7efeb2b77c4..bfca993deb70 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
@@ -317,8 +317,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, \
}
@@ -333,8 +331,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, \
}
@@ -344,8 +340,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), \
}
/* qseed2 is not supported, so disabled scaling */
@@ -360,8 +354,6 @@ static const u32 wb2_formats_rgb_yuv[] = {
.base = 0x320, .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, \
}
@@ -373,8 +365,6 @@ static const u32 wb2_formats_rgb_yuv[] = {
.base = 0x200, .len = 0x28,}, \
.format_list = plane_formats, \
.num_formats = ARRAY_SIZE(plane_formats), \
- .virt_format_list = plane_formats, \
- .virt_num_formats = ARRAY_SIZE(plane_formats), \
}
#define _DMA_SBLK() \
@@ -383,8 +373,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 817e98bc6997..78ae3a9f22f9 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.5
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v6 4/9] drm/msm/dpu: move scaling limitations out of the hw_catalog
2024-10-25 0:20 [PATCH v6 0/9] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
` (2 preceding siblings ...)
2024-10-25 0:20 ` [PATCH v6 3/9] drm/msm/dpu: drop virt_formats from SSPP subblock configuration Dmitry Baryshkov
@ 2024-10-25 0:20 ` Dmitry Baryshkov
2024-10-25 23:15 ` Abhinav Kumar
2024-10-25 0:20 ` [PATCH v6 5/9] drm/msm/dpu: split dpu_plane_atomic_check() Dmitry Baryshkov
` (5 subsequent siblings)
9 siblings, 1 reply; 30+ messages in thread
From: Dmitry Baryshkov @ 2024-10-25 0:20 UTC (permalink / raw)
To: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten, David Airlie,
Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
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 | 16 ----------------
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(+), 23 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 bfca993deb70..2cbf41f33cc0 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
@@ -147,10 +147,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[] = {
@@ -308,8 +304,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,}, \
@@ -322,8 +316,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,}, \
@@ -336,8 +328,6 @@ static const u32 wb2_formats_rgb_yuv[] = {
#define _VIG_SBLK_NOSCALE() \
{ \
- .maxdwnscale = SSPP_UNITY_SCALE, \
- .maxupscale = SSPP_UNITY_SCALE, \
.format_list = plane_formats, \
.num_formats = ARRAY_SIZE(plane_formats), \
}
@@ -345,8 +335,6 @@ static const u32 wb2_formats_rgb_yuv[] = {
/* qseed2 is not supported, so disabled scaling */
#define _VIG_SBLK_QSEED2() \
{ \
- .maxdwnscale = SSPP_UNITY_SCALE, \
- .maxupscale = SSPP_UNITY_SCALE, \
.scaler_blk = {.name = "scaler", \
/* no version for qseed2 */ \
.base = 0x200, .len = 0xa0,}, \
@@ -359,8 +347,6 @@ static const u32 wb2_formats_rgb_yuv[] = {
#define _RGB_SBLK() \
{ \
- .maxdwnscale = SSPP_UNITY_SCALE, \
- .maxupscale = SSPP_UNITY_SCALE, \
.scaler_blk = {.name = "scaler", \
.base = 0x200, .len = 0x28,}, \
.format_list = plane_formats, \
@@ -369,8 +355,6 @@ static const u32 wb2_formats_rgb_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 78ae3a9f22f9..c701d18c3522 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 725c9a5826fd..8a9e8a430da7 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -777,12 +777,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 i, ret = 0, min_scale;
+ int i, 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;
@@ -813,10 +816,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 = DRM_PLANE_NO_SCALING;
+ max_scale = DRM_PLANE_NO_SCALING;
+ }
+
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.5
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v6 5/9] drm/msm/dpu: split dpu_plane_atomic_check()
2024-10-25 0:20 [PATCH v6 0/9] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
` (3 preceding siblings ...)
2024-10-25 0:20 ` [PATCH v6 4/9] drm/msm/dpu: move scaling limitations out of the hw_catalog Dmitry Baryshkov
@ 2024-10-25 0:20 ` Dmitry Baryshkov
2024-10-25 23:21 ` Abhinav Kumar
2024-10-25 0:20 ` [PATCH v6 6/9] drm/msm/dpu: move rot90 checking to dpu_plane_atomic_check_sspp() Dmitry Baryshkov
` (4 subsequent siblings)
9 siblings, 1 reply; 30+ messages in thread
From: Dmitry Baryshkov @ 2024-10-25 0:20 UTC (permalink / raw)
To: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten, David Airlie,
Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
Split dpu_plane_atomic_check() function into two pieces:
dpu_plane_atomic_check_nosspp() performing generic checks on the pstate,
without touching the associated SSPP blocks,
and
dpu_plane_atomic_check_sspp(), which takes into account used SSPPs.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 178 +++++++++++++++++++-----------
1 file changed, 112 insertions(+), 66 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index 8a9e8a430da7..a5f29851361f 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -780,49 +780,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_nosspp(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 i, 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_sw_pipe *pipe = &pstate->pipe;
- struct dpu_sw_pipe *r_pipe = &pstate->r_pipe;
- const struct drm_crtc_state *crtc_state = NULL;
- const struct msm_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(&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 = DRM_PLANE_NO_SCALING;
- max_scale = DRM_PLANE_NO_SCALING;
- }
+ 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,
@@ -835,11 +808,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",
@@ -873,8 +841,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
if (pstate->layout.plane_pitch[i] > DPU_SSPP_MAX_PITCH_SIZE)
return -E2BIG;
- fmt = msm_framebuffer_format(new_plane_state->fb);
-
max_linewidth = pdpu->catalog->caps->max_linewidth;
drm_rect_rotate(&pipe_cfg->src_rect,
@@ -883,6 +849,78 @@ 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_sspp(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 msm_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;
+
+ fmt = 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 (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
@@ -896,12 +934,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) &&
@@ -923,26 +955,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)
@@ -965,11 +977,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);
+
+ pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
+ r_pipe->sspp = NULL;
+
+ ret = dpu_plane_atomic_check_nosspp(plane, new_plane_state, crtc_state);
+ if (ret)
+ return ret;
+
+ 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;
+
+ return dpu_plane_atomic_check_sspp(plane, state, crtc_state);
+}
+
static void dpu_plane_flush_csc(struct dpu_plane *pdpu, struct dpu_sw_pipe *pipe)
{
const struct msm_format *format =
--
2.39.5
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v6 6/9] drm/msm/dpu: move rot90 checking to dpu_plane_atomic_check_sspp()
2024-10-25 0:20 [PATCH v6 0/9] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
` (4 preceding siblings ...)
2024-10-25 0:20 ` [PATCH v6 5/9] drm/msm/dpu: split dpu_plane_atomic_check() Dmitry Baryshkov
@ 2024-10-25 0:20 ` Dmitry Baryshkov
2024-10-29 21:00 ` Abhinav Kumar
2024-10-25 0:20 ` [PATCH v6 7/9] drm/msm/dpu: add support for virtual planes Dmitry Baryshkov
` (3 subsequent siblings)
9 siblings, 1 reply; 30+ messages in thread
From: Dmitry Baryshkov @ 2024-10-25 0:20 UTC (permalink / raw)
To: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten, David Airlie,
Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
Move a call to dpu_plane_check_inline_rotation() to the
dpu_plane_atomic_check_sspp() function, so that the rot90 constraints
are checked for both SSPP blocks. 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 8998d1862e16..9ae475420c05 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h
@@ -144,10 +144,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 a5f29851361f..5e230391fabc 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -528,8 +528,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 msm_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->pixel_format);
@@ -552,7 +551,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,
@@ -604,7 +603,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);
}
/**
@@ -696,12 +695,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 msm_format *fmt)
+ struct dpu_sw_pipe *pipe,
+ struct drm_rect src,
+ const struct msm_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;
@@ -731,6 +735,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 = MSM_FORMAT_IS_YUV(fmt) ? 2 : 1;
@@ -768,6 +773,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");
@@ -891,7 +902,6 @@ static int dpu_plane_atomic_check_sspp(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;
@@ -915,6 +925,15 @@ static int dpu_plane_atomic_check_sspp(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)
@@ -938,6 +957,7 @@ static int dpu_plane_atomic_check_sspp(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 ||
MSM_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);
@@ -961,23 +981,6 @@ static int dpu_plane_atomic_check_sspp(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;
}
@@ -1117,14 +1120,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 348b0075d1ce..31ee8b55c4dd 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
* @layout: framebuffer memory layout
*/
struct dpu_plane_state {
@@ -48,7 +47,6 @@ struct dpu_plane_state {
u64 plane_clk;
bool needs_dirtyfb;
- unsigned int rotation;
struct dpu_hw_fmt_layout layout;
};
--
2.39.5
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v6 7/9] drm/msm/dpu: add support for virtual planes
2024-10-25 0:20 [PATCH v6 0/9] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
` (5 preceding siblings ...)
2024-10-25 0:20 ` [PATCH v6 6/9] drm/msm/dpu: move rot90 checking to dpu_plane_atomic_check_sspp() Dmitry Baryshkov
@ 2024-10-25 0:20 ` Dmitry Baryshkov
2024-10-29 21:30 ` Abhinav Kumar
2024-10-25 0:20 ` [PATCH v6 8/9] drm/msm/dpu: allow using two SSPP blocks for a single plane Dmitry Baryshkov
` (2 subsequent siblings)
9 siblings, 1 reply; 30+ messages in thread
From: Dmitry Baryshkov @ 2024-10-25 0:20 UTC (permalink / raw)
To: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten, David Airlie,
Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
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.
As the planes are attached to the CRTC and not the encoder, the SSPP
blocks are also allocated per CRTC ID (all other resources are currently
allocated per encoder ID). This also matches the hardware requirement,
where both rectangles of a single SSPP can only be used with the LM
pair.
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 | 237 ++++++++++++++++++++++++++----
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 16 ++
drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 68 +++++++++
drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 27 ++++
7 files changed, 383 insertions(+), 29 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 58595dcc3889..a7eea094aa14 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -1166,6 +1166,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)
{
@@ -1181,6 +1224,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 15679dd50c66..70757d876cc3 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;
+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);
@@ -814,8 +817,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 935ff6fd172c..479d4c172290 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
@@ -54,6 +54,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;
@@ -128,6 +130,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 5e230391fabc..125db3803cf5 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -878,7 +878,7 @@ static int dpu_plane_atomic_check_nosspp(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);
@@ -1001,8 +1001,13 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
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 (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_nosspp(plane, new_plane_state, crtc_state);
if (ret)
@@ -1019,6 +1024,112 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
return dpu_plane_atomic_check_sspp(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 drm_plane_state *old_plane_state =
+ drm_atomic_get_old_plane_state(state, plane);
+ struct dpu_plane_state *pstate = to_dpu_plane_state(plane_state);
+ struct drm_crtc_state *crtc_state;
+ int ret;
+
+ if (plane_state->crtc)
+ crtc_state = drm_atomic_get_new_crtc_state(state,
+ plane_state->crtc);
+
+ ret = dpu_plane_atomic_check_nosspp(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;
+ }
+
+ /* force resource reallocation if the format of FB has changed */
+ if (!old_plane_state || !old_plane_state->fb ||
+ msm_framebuffer_format(old_plane_state->fb) !=
+ msm_framebuffer_format(plane_state->fb))
+ crtc_state->planes_changed = true;
+
+ 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 msm_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 = msm_framebuffer_format(plane_state->fb);
+ reqs.yuv = MSM_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_sspp(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 msm_format *format =
@@ -1331,12 +1442,15 @@ 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);
@@ -1429,31 +1543,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,
@@ -1479,7 +1591,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,
@@ -1487,10 +1599,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 31ee8b55c4dd..6d310bd9db30 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
@@ -78,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
@@ -94,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..feeef9d31653 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
@@ -694,6 +694,74 @@ int dpu_rm_reserve(
return ret;
}
+static struct dpu_hw_sspp *dpu_rm_try_sspp(struct dpu_rm *rm,
+ struct dpu_global_state *global_state,
+ struct drm_crtc *crtc,
+ struct dpu_rm_sspp_requirements *reqs,
+ unsigned int type)
+{
+ uint32_t crtc_id = crtc->base.id;
+ struct dpu_hw_sspp *hw_sspp;
+ int i;
+
+ 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];
+
+ if (hw_sspp->cap->type != type)
+ continue;
+
+ if (reqs->scale && !hw_sspp->cap->sblk->scaler_blk.len)
+ continue;
+
+ // TODO: QSEED2 and RGB scalers are not yet supported
+ if (reqs->scale && !hw_sspp->ops.setup_scaler)
+ continue;
+
+ if (reqs->yuv && !hw_sspp->cap->sblk->csc_blk.len)
+ continue;
+
+ if (reqs->rot90 && !(hw_sspp->cap->features & DPU_SSPP_INLINE_ROTATION))
+ continue;
+
+ global_state->sspp_to_crtc_id[i] = crtc_id;
+
+ return rm->hw_sspp[i];
+ }
+
+ return NULL;
+}
+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)
+{
+ struct dpu_hw_sspp *hw_sspp = NULL;
+
+ if (!reqs->scale && !reqs->yuv)
+ hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_DMA);
+ if (!hw_sspp && reqs->scale)
+ hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_RGB);
+ if (!hw_sspp)
+ hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_VIG);
+
+ return hw_sspp;
+}
+
+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..6edff89fe83a 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,27 @@ 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
+ */
+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.5
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v6 8/9] drm/msm/dpu: allow using two SSPP blocks for a single plane
2024-10-25 0:20 [PATCH v6 0/9] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
` (6 preceding siblings ...)
2024-10-25 0:20 ` [PATCH v6 7/9] drm/msm/dpu: add support for virtual planes Dmitry Baryshkov
@ 2024-10-25 0:20 ` Dmitry Baryshkov
2024-10-29 22:07 ` Abhinav Kumar
2024-10-25 0:20 ` [PATCH v6 9/9] drm/msm/dpu: include SSPP allocation state into the dumped state Dmitry Baryshkov
2024-11-02 1:08 ` [PATCH v6 0/9] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
9 siblings, 1 reply; 30+ messages in thread
From: Dmitry Baryshkov @ 2024-10-25 0:20 UTC (permalink / raw)
To: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten, David Airlie,
Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
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 | 163 ++++++++++++++++++++++--------
1 file changed, 119 insertions(+), 44 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index 125db3803cf5..ad6cc469f475 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -20,7 +20,6 @@
#include "msm_drv.h"
#include "msm_mdss.h"
#include "dpu_kms.h"
-#include "dpu_formats.h"
#include "dpu_hw_sspp.h"
#include "dpu_hw_util.h"
#include "dpu_trace.h"
@@ -888,6 +887,28 @@ static int dpu_plane_atomic_check_nosspp(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 msm_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 (MSM_FORMAT_IS_YUV(fmt))
+ return false;
+
+ if (MSM_FORMAT_IS_UBWC(fmt) &&
+ drm_rect_width(&pipe_cfg->src_rect) > max_linewidth / 2)
+ return false;
+
+ return true;
+}
+
static int dpu_plane_atomic_check_sspp(struct drm_plane *plane,
struct drm_atomic_state *state,
const struct drm_crtc_state *crtc_state)
@@ -901,7 +922,6 @@ static int dpu_plane_atomic_check_sspp(struct drm_plane *plane,
const struct msm_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;
@@ -923,8 +943,6 @@ static int dpu_plane_atomic_check_sspp(struct drm_plane *plane,
fmt = 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))
@@ -940,41 +958,6 @@ static int dpu_plane_atomic_check_sspp(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 (MSM_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 ||
- MSM_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)
@@ -995,16 +978,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;
@@ -1021,6 +1004,49 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
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 msm_format *fmt;
+
+ fmt = 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 (MSM_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 ||
+ MSM_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.
+ */
+ 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;
+ }
+
return dpu_plane_atomic_check_sspp(plane, state, crtc_state);
}
@@ -1054,8 +1080,16 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
return 0;
}
- /* force resource reallocation if the format of FB has changed */
+ /*
+ * Force resource reallocation if the format of FB or src/dst have
+ * changed. We might need to allocate different SSPP or SSPPs for this
+ * plane than the one used previously.
+ */
if (!old_plane_state || !old_plane_state->fb ||
+ old_plane_state->src_w != plane_state->src_w ||
+ old_plane_state->src_h != plane_state->src_h ||
+ old_plane_state->src_w != plane_state->src_w ||
+ old_plane_state->crtc_h != plane_state->crtc_h ||
msm_framebuffer_format(old_plane_state->fb) !=
msm_framebuffer_format(plane_state->fb))
crtc_state->planes_changed = true;
@@ -1075,7 +1109,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 msm_format *fmt;
+ uint32_t max_linewidth;
if (plane_state->crtc)
crtc_state = drm_atomic_get_new_crtc_state(state,
@@ -1084,6 +1121,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;
@@ -1098,10 +1137,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_sspp(plane, state, crtc_state);
}
--
2.39.5
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v6 9/9] drm/msm/dpu: include SSPP allocation state into the dumped state
2024-10-25 0:20 [PATCH v6 0/9] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
` (7 preceding siblings ...)
2024-10-25 0:20 ` [PATCH v6 8/9] drm/msm/dpu: allow using two SSPP blocks for a single plane Dmitry Baryshkov
@ 2024-10-25 0:20 ` Dmitry Baryshkov
2024-11-02 1:08 ` [PATCH v6 0/9] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
9 siblings, 0 replies; 30+ messages in thread
From: Dmitry Baryshkov @ 2024-10-25 0:20 UTC (permalink / raw)
To: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten, David Airlie,
Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
Make dpu_rm_print_state() also output the SSPP allocation state.
Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
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 feeef9d31653..e5b0abe515ff 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
@@ -881,4 +881,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.5
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: [PATCH v6 2/9] drm/msm/dpu: move pstate->pipe initialization to dpu_plane_atomic_check
2024-10-25 0:20 ` [PATCH v6 2/9] drm/msm/dpu: move pstate->pipe initialization to dpu_plane_atomic_check Dmitry Baryshkov
@ 2024-10-25 19:00 ` Abhinav Kumar
2024-10-28 10:46 ` Dmitry Baryshkov
0 siblings, 1 reply; 30+ messages in thread
From: Abhinav Kumar @ 2024-10-25 19:00 UTC (permalink / raw)
To: Dmitry Baryshkov, Rob Clark, Sean Paul, Marijn Suijten,
David Airlie, Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
On 10/24/2024 5:20 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.
>
I had R-bed this in v5. Did anything change in v6?
But one comment below.
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 25 +++++++++++--------------
> 1 file changed, 11 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 37faf5b238b0..725c9a5826fd 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> @@ -797,13 +797,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(&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,
Do you think it will be better to move the get_sspp() call after the
drm_atomic_helper_check_plane_state()?
> @@ -820,7 +829,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) {
> @@ -1286,7 +1294,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");
> @@ -1308,16 +1315,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] 30+ messages in thread
* Re: [PATCH v6 4/9] drm/msm/dpu: move scaling limitations out of the hw_catalog
2024-10-25 0:20 ` [PATCH v6 4/9] drm/msm/dpu: move scaling limitations out of the hw_catalog Dmitry Baryshkov
@ 2024-10-25 23:15 ` Abhinav Kumar
0 siblings, 0 replies; 30+ messages in thread
From: Abhinav Kumar @ 2024-10-25 23:15 UTC (permalink / raw)
To: Dmitry Baryshkov, Rob Clark, Sean Paul, Marijn Suijten,
David Airlie, Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
On 10/24/2024 5:20 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 | 16 ----------------
> 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(+), 23 deletions(-)
>
This was also R-bed in v5 and I dont see anything changed, LGTM anyway
Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v6 5/9] drm/msm/dpu: split dpu_plane_atomic_check()
2024-10-25 0:20 ` [PATCH v6 5/9] drm/msm/dpu: split dpu_plane_atomic_check() Dmitry Baryshkov
@ 2024-10-25 23:21 ` Abhinav Kumar
0 siblings, 0 replies; 30+ messages in thread
From: Abhinav Kumar @ 2024-10-25 23:21 UTC (permalink / raw)
To: Dmitry Baryshkov, Rob Clark, Sean Paul, Marijn Suijten,
David Airlie, Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
On 10/24/2024 5:20 PM, Dmitry Baryshkov wrote:
> Split dpu_plane_atomic_check() function into two pieces:
>
> dpu_plane_atomic_check_nosspp() performing generic checks on the pstate,
> without touching the associated SSPP blocks,
>
> and
>
> dpu_plane_atomic_check_sspp(), which takes into account used SSPPs.
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 178 +++++++++++++++++++-----------
> 1 file changed, 112 insertions(+), 66 deletions(-)
>
Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v6 2/9] drm/msm/dpu: move pstate->pipe initialization to dpu_plane_atomic_check
2024-10-25 19:00 ` Abhinav Kumar
@ 2024-10-28 10:46 ` Dmitry Baryshkov
2024-10-29 20:42 ` Abhinav Kumar
0 siblings, 1 reply; 30+ messages in thread
From: Dmitry Baryshkov @ 2024-10-28 10:46 UTC (permalink / raw)
To: Abhinav Kumar
Cc: Rob Clark, Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
linux-arm-msm, dri-devel, freedreno, linux-kernel
On Fri, Oct 25, 2024 at 12:00:20PM -0700, Abhinav Kumar wrote:
>
>
> On 10/24/2024 5:20 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.
> >
>
> I had R-bed this in v5. Did anything change in v6?
No, nothing. I'm sorry for forgetting to run `b4 trailers -u`.
> But one comment below.
>
> > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > ---
> > drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 25 +++++++++++--------------
> > 1 file changed, 11 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 37faf5b238b0..725c9a5826fd 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > @@ -797,13 +797,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(&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,
>
> Do you think it will be better to move the get_sspp() call after the
> drm_atomic_helper_check_plane_state()?
I'd say, it makes no difference. I'll check your suggestion if I have to
send another iteration.
>
> > @@ -820,7 +829,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) {
> > @@ -1286,7 +1294,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");
> > @@ -1308,16 +1315,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);
> > }
> >
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v6 2/9] drm/msm/dpu: move pstate->pipe initialization to dpu_plane_atomic_check
2024-10-28 10:46 ` Dmitry Baryshkov
@ 2024-10-29 20:42 ` Abhinav Kumar
0 siblings, 0 replies; 30+ messages in thread
From: Abhinav Kumar @ 2024-10-29 20:42 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Rob Clark, Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
linux-arm-msm, dri-devel, freedreno, linux-kernel
On 10/28/2024 3:46 AM, Dmitry Baryshkov wrote:
> On Fri, Oct 25, 2024 at 12:00:20PM -0700, Abhinav Kumar wrote:
>>
>>
>> On 10/24/2024 5:20 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.
>>>
>>
>> I had R-bed this in v5. Did anything change in v6?
>
> No, nothing. I'm sorry for forgetting to run `b4 trailers -u`.
>
>> But one comment below.
>>
>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>> ---
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 25 +++++++++++--------------
>>> 1 file changed, 11 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 37faf5b238b0..725c9a5826fd 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>> @@ -797,13 +797,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(&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,
>>
>> Do you think it will be better to move the get_sspp() call after the
>> drm_atomic_helper_check_plane_state()?
>
> I'd say, it makes no difference. I'll check your suggestion if I have to
> send another iteration.
>
Ok, its a minor comment, I am fine with this change otherwise,
Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
If you do need to push another version, you can explore that.
>>
>>> @@ -820,7 +829,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) {
>>> @@ -1286,7 +1294,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");
>>> @@ -1308,16 +1315,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] 30+ messages in thread
* Re: [PATCH v6 6/9] drm/msm/dpu: move rot90 checking to dpu_plane_atomic_check_sspp()
2024-10-25 0:20 ` [PATCH v6 6/9] drm/msm/dpu: move rot90 checking to dpu_plane_atomic_check_sspp() Dmitry Baryshkov
@ 2024-10-29 21:00 ` Abhinav Kumar
0 siblings, 0 replies; 30+ messages in thread
From: Abhinav Kumar @ 2024-10-29 21:00 UTC (permalink / raw)
To: Dmitry Baryshkov, Rob Clark, Sean Paul, Marijn Suijten,
David Airlie, Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
On 10/24/2024 5:20 PM, Dmitry Baryshkov wrote:
> Move a call to dpu_plane_check_inline_rotation() to the
> dpu_plane_atomic_check_sspp() function, so that the rot90 constraints
> are checked for both SSPP blocks. 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(-)
>
Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v6 7/9] drm/msm/dpu: add support for virtual planes
2024-10-25 0:20 ` [PATCH v6 7/9] drm/msm/dpu: add support for virtual planes Dmitry Baryshkov
@ 2024-10-29 21:30 ` Abhinav Kumar
2024-10-30 10:48 ` Dmitry Baryshkov
0 siblings, 1 reply; 30+ messages in thread
From: Abhinav Kumar @ 2024-10-29 21:30 UTC (permalink / raw)
To: Dmitry Baryshkov, Rob Clark, Sean Paul, Marijn Suijten,
David Airlie, Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
On 10/24/2024 5:20 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.
>
> As the planes are attached to the CRTC and not the encoder, the SSPP
> blocks are also allocated per CRTC ID (all other resources are currently
> allocated per encoder ID). This also matches the hardware requirement,
> where both rectangles of a single SSPP can only be used with the LM
> pair.
>
> 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 | 237 ++++++++++++++++++++++++++----
> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 16 ++
> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 68 +++++++++
> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 27 ++++
> 7 files changed, 383 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> index 58595dcc3889..a7eea094aa14 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> @@ -1166,6 +1166,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)
> {
> @@ -1181,6 +1224,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;
> + }
planes_changed is set only for format changes . Will it cover all
needs_modeset cases?
OR do we also need to set planes_changed when
drm_atomic_crtc_needs_modeset()?
Unless I am missing something, I think we have to otherwise sspp
reallocation wont happen in modeset cases.
Overall, mainly we want to make sure SSPPs are re-assigned when:
1) format changes (RGB to YUV and vice-versa)
2) Any modesets
3) Any disable/enable without modeset like connectors changed as SSPPs
are changing outputs there.
If we are covered for all these, let me know.
> +
> 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 15679dd50c66..70757d876cc3 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;
> +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);
>
> @@ -814,8 +817,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 935ff6fd172c..479d4c172290 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
> @@ -54,6 +54,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;
> @@ -128,6 +130,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];
> };
This is the part which now looks odd and can be managed with rebase I guess.
Are you planning to pull in the move resource allocation to crtc_id
changes first before this part? IOW, rebase this change on top of that?
That will look clean because if this goes in first now, the crtc_id
allocation changes will need to be rebased which I dont know who will do
now as Jessica is OOO.
>
> 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 5e230391fabc..125db3803cf5 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> @@ -878,7 +878,7 @@ static int dpu_plane_atomic_check_nosspp(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);
> @@ -1001,8 +1001,13 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> 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 (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_nosspp(plane, new_plane_state, crtc_state);
> if (ret)
> @@ -1019,6 +1024,112 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> return dpu_plane_atomic_check_sspp(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 drm_plane_state *old_plane_state =
> + drm_atomic_get_old_plane_state(state, plane);
> + struct dpu_plane_state *pstate = to_dpu_plane_state(plane_state);
> + struct drm_crtc_state *crtc_state;
> + int ret;
> +
> + if (plane_state->crtc)
> + crtc_state = drm_atomic_get_new_crtc_state(state,
> + plane_state->crtc);
> +
> + ret = dpu_plane_atomic_check_nosspp(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;
> + }
> +
> + /* force resource reallocation if the format of FB has changed */
> + if (!old_plane_state || !old_plane_state->fb ||
> + msm_framebuffer_format(old_plane_state->fb) !=
> + msm_framebuffer_format(plane_state->fb))
> + crtc_state->planes_changed = true;
> +
> + 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 msm_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 = msm_framebuffer_format(plane_state->fb);
> + reqs.yuv = MSM_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_sspp(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 msm_format *format =
> @@ -1331,12 +1442,15 @@ 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);
> @@ -1429,31 +1543,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,
> @@ -1479,7 +1591,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,
> @@ -1487,10 +1599,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 31ee8b55c4dd..6d310bd9db30 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> @@ -78,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
> @@ -94,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..feeef9d31653 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> @@ -694,6 +694,74 @@ int dpu_rm_reserve(
> return ret;
> }
>
> +static struct dpu_hw_sspp *dpu_rm_try_sspp(struct dpu_rm *rm,
> + struct dpu_global_state *global_state,
> + struct drm_crtc *crtc,
> + struct dpu_rm_sspp_requirements *reqs,
> + unsigned int type)
> +{
> + uint32_t crtc_id = crtc->base.id;
> + struct dpu_hw_sspp *hw_sspp;
> + int i;
> +
> + 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];
> +
> + if (hw_sspp->cap->type != type)
> + continue;
> +
> + if (reqs->scale && !hw_sspp->cap->sblk->scaler_blk.len)
> + continue;
We are already requesting a relevant SSPP when scale is needed so is
this needed?
> +
> + // TODO: QSEED2 and RGB scalers are not yet supported
> + if (reqs->scale && !hw_sspp->ops.setup_scaler)
> + continue;
> +
same here
> + if (reqs->yuv && !hw_sspp->cap->sblk->csc_blk.len)
> + continue;
same here
> +
> + if (reqs->rot90 && !(hw_sspp->cap->features & DPU_SSPP_INLINE_ROTATION))
> + continue;
> +
> + global_state->sspp_to_crtc_id[i] = crtc_id;
> +
> + return rm->hw_sspp[i];
> + }
> +
> + return NULL;
> +}
> +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)
> +{
> + struct dpu_hw_sspp *hw_sspp = NULL;
> +
> + if (!reqs->scale && !reqs->yuv)
> + hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_DMA);
> + if (!hw_sspp && reqs->scale)
> + hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_RGB);
I dont recollect whether RGB SSPPs supported scaling, if you have any
source or link for this, that would help me for sure.
But even otherwise, I dont see any chipset in the catalog setting this
SSPP type, so do we need to add this case?
Overall, I am happier with this version which elimiates the hweight.
> + if (!hw_sspp)
> + hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_VIG);
> +
> + return hw_sspp;
> +}
> +
> +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..6edff89fe83a 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,27 @@ 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
> + */
> +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] 30+ messages in thread
* Re: [PATCH v6 8/9] drm/msm/dpu: allow using two SSPP blocks for a single plane
2024-10-25 0:20 ` [PATCH v6 8/9] drm/msm/dpu: allow using two SSPP blocks for a single plane Dmitry Baryshkov
@ 2024-10-29 22:07 ` Abhinav Kumar
2024-10-30 10:03 ` Dmitry Baryshkov
0 siblings, 1 reply; 30+ messages in thread
From: Abhinav Kumar @ 2024-10-29 22:07 UTC (permalink / raw)
To: Dmitry Baryshkov, Rob Clark, Sean Paul, Marijn Suijten,
David Airlie, Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
On 10/24/2024 5:20 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 | 163 ++++++++++++++++++++++--------
> 1 file changed, 119 insertions(+), 44 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> index 125db3803cf5..ad6cc469f475 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> @@ -20,7 +20,6 @@
> #include "msm_drv.h"
> #include "msm_mdss.h"
> #include "dpu_kms.h"
> -#include "dpu_formats.h"
> #include "dpu_hw_sspp.h"
> #include "dpu_hw_util.h"
> #include "dpu_trace.h"
> @@ -888,6 +887,28 @@ static int dpu_plane_atomic_check_nosspp(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 msm_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 (MSM_FORMAT_IS_YUV(fmt))
> + return false;
> +
> + if (MSM_FORMAT_IS_UBWC(fmt) &&
> + drm_rect_width(&pipe_cfg->src_rect) > max_linewidth / 2)
> + return false;
> +
> + return true;
> +}
Dont we also need to check for
if (!test_bit(DPU_SSPP_SMART_DMA_V1, &pipe->sspp->cap->features) &&
!test_bit(DPU_SSPP_SMART_DMA_V2, &pipe->sspp->cap->features))?
return false;
> +
> static int dpu_plane_atomic_check_sspp(struct drm_plane *plane,
> struct drm_atomic_state *state,
> const struct drm_crtc_state *crtc_state)
> @@ -901,7 +922,6 @@ static int dpu_plane_atomic_check_sspp(struct drm_plane *plane,
> const struct msm_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;
> @@ -923,8 +943,6 @@ static int dpu_plane_atomic_check_sspp(struct drm_plane *plane,
>
> fmt = 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))
> @@ -940,41 +958,6 @@ static int dpu_plane_atomic_check_sspp(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 (MSM_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 ||
> - MSM_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)
> @@ -995,16 +978,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;
> @@ -1021,6 +1004,49 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> 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 msm_format *fmt;
> +
> + fmt = 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 (MSM_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 ||
> + MSM_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;
> + }
Dont the above two conditions translate to
!dpu_plane_is_multirect_parallel_capable()?
I think once we have a unified plane atomic check and not a separate one
for virtual planes (we had to add one to support the modparam), some
duplication will go away but till then I think this is the best we can do.
> +
> + /*
> + * Use multirect for wide plane. We do not support dynamic
> + * assignment of SSPPs, so we know the configuration.
> + */
> + 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;
> + }
> +
> return dpu_plane_atomic_check_sspp(plane, state, crtc_state);
> }
>
> @@ -1054,8 +1080,16 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
> return 0;
> }
>
> - /* force resource reallocation if the format of FB has changed */
> + /*
> + * Force resource reallocation if the format of FB or src/dst have
> + * changed. We might need to allocate different SSPP or SSPPs for this
> + * plane than the one used previously.
> + */
> if (!old_plane_state || !old_plane_state->fb ||
> + old_plane_state->src_w != plane_state->src_w ||
> + old_plane_state->src_h != plane_state->src_h ||
> + old_plane_state->src_w != plane_state->src_w ||
> + old_plane_state->crtc_h != plane_state->crtc_h ||
> msm_framebuffer_format(old_plane_state->fb) !=
> msm_framebuffer_format(plane_state->fb))
> crtc_state->planes_changed = true;
> @@ -1075,7 +1109,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 msm_format *fmt;
> + uint32_t max_linewidth;
>
> if (plane_state->crtc)
> crtc_state = drm_atomic_get_new_crtc_state(state,
> @@ -1084,6 +1121,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;
> @@ -1098,10 +1137,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_sspp(plane, state, crtc_state);
> }
>
>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v6 8/9] drm/msm/dpu: allow using two SSPP blocks for a single plane
2024-10-29 22:07 ` Abhinav Kumar
@ 2024-10-30 10:03 ` Dmitry Baryshkov
0 siblings, 0 replies; 30+ messages in thread
From: Dmitry Baryshkov @ 2024-10-30 10:03 UTC (permalink / raw)
To: Abhinav Kumar
Cc: Rob Clark, Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
linux-arm-msm, dri-devel, freedreno, linux-kernel
On Tue, Oct 29, 2024 at 03:07:30PM -0700, Abhinav Kumar wrote:
>
>
> On 10/24/2024 5:20 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 | 163 ++++++++++++++++++++++--------
> > 1 file changed, 119 insertions(+), 44 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > index 125db3803cf5..ad6cc469f475 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > @@ -20,7 +20,6 @@
> > #include "msm_drv.h"
> > #include "msm_mdss.h"
> > #include "dpu_kms.h"
> > -#include "dpu_formats.h"
> > #include "dpu_hw_sspp.h"
> > #include "dpu_hw_util.h"
> > #include "dpu_trace.h"
> > @@ -888,6 +887,28 @@ static int dpu_plane_atomic_check_nosspp(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 msm_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 (MSM_FORMAT_IS_YUV(fmt))
> > + return false;
> > +
> > + if (MSM_FORMAT_IS_UBWC(fmt) &&
> > + drm_rect_width(&pipe_cfg->src_rect) > max_linewidth / 2)
> > + return false;
> > +
> > + return true;
> > +}
>
> Dont we also need to check for
>
> if (!test_bit(DPU_SSPP_SMART_DMA_V1, &pipe->sspp->cap->features) &&
> !test_bit(DPU_SSPP_SMART_DMA_V2, &pipe->sspp->cap->features))?
> return false;
In the patch I was checking that after a call to this function, but
maybe you are right. Especially since I was checking only the pipe, not
the r_pipe.
>
> > +
> > static int dpu_plane_atomic_check_sspp(struct drm_plane *plane,
> > struct drm_atomic_state *state,
> > const struct drm_crtc_state *crtc_state)
> > @@ -901,7 +922,6 @@ static int dpu_plane_atomic_check_sspp(struct drm_plane *plane,
> > const struct msm_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;
> > @@ -923,8 +943,6 @@ static int dpu_plane_atomic_check_sspp(struct drm_plane *plane,
> > fmt = 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))
> > @@ -940,41 +958,6 @@ static int dpu_plane_atomic_check_sspp(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 (MSM_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 ||
> > - MSM_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)
> > @@ -995,16 +978,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;
> > @@ -1021,6 +1004,49 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> > 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 msm_format *fmt;
> > +
> > + fmt = 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 (MSM_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 ||
> > + MSM_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;
> > + }
>
> Dont the above two conditions translate to
> !dpu_plane_is_multirect_parallel_capable()?
Good idea, I'll change that.
>
> I think once we have a unified plane atomic check and not a separate one for
> virtual planes (we had to add one to support the modparam), some duplication
> will go away but till then I think this is the best we can do.
>
>
> > +
> > + /*
> > + * Use multirect for wide plane. We do not support dynamic
> > + * assignment of SSPPs, so we know the configuration.
> > + */
> > + 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;
> > + }
> > +
> > return dpu_plane_atomic_check_sspp(plane, state, crtc_state);
> > }
> > @@ -1054,8 +1080,16 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
> > return 0;
> > }
> > - /* force resource reallocation if the format of FB has changed */
> > + /*
> > + * Force resource reallocation if the format of FB or src/dst have
> > + * changed. We might need to allocate different SSPP or SSPPs for this
> > + * plane than the one used previously.
> > + */
> > if (!old_plane_state || !old_plane_state->fb ||
> > + old_plane_state->src_w != plane_state->src_w ||
> > + old_plane_state->src_h != plane_state->src_h ||
> > + old_plane_state->src_w != plane_state->src_w ||
> > + old_plane_state->crtc_h != plane_state->crtc_h ||
> > msm_framebuffer_format(old_plane_state->fb) !=
> > msm_framebuffer_format(plane_state->fb))
> > crtc_state->planes_changed = true;
> > @@ -1075,7 +1109,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 msm_format *fmt;
> > + uint32_t max_linewidth;
> > if (plane_state->crtc)
> > crtc_state = drm_atomic_get_new_crtc_state(state,
> > @@ -1084,6 +1121,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;
> > @@ -1098,10 +1137,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_sspp(plane, state, crtc_state);
> > }
> >
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v6 7/9] drm/msm/dpu: add support for virtual planes
2024-10-29 21:30 ` Abhinav Kumar
@ 2024-10-30 10:48 ` Dmitry Baryshkov
2024-10-30 19:26 ` Abhinav Kumar
0 siblings, 1 reply; 30+ messages in thread
From: Dmitry Baryshkov @ 2024-10-30 10:48 UTC (permalink / raw)
To: Abhinav Kumar
Cc: Rob Clark, Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
linux-arm-msm, dri-devel, freedreno, linux-kernel
On Tue, Oct 29, 2024 at 02:30:12PM -0700, Abhinav Kumar wrote:
>
>
> On 10/24/2024 5:20 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.
> >
> > As the planes are attached to the CRTC and not the encoder, the SSPP
> > blocks are also allocated per CRTC ID (all other resources are currently
> > allocated per encoder ID). This also matches the hardware requirement,
> > where both rectangles of a single SSPP can only be used with the LM
> > pair.
> >
> > 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 | 237 ++++++++++++++++++++++++++----
> > drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 16 ++
> > drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 68 +++++++++
> > drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 27 ++++
> > 7 files changed, 383 insertions(+), 29 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > index 58595dcc3889..a7eea094aa14 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > @@ -1166,6 +1166,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)
> > {
> > @@ -1181,6 +1224,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;
> > + }
>
> planes_changed is set only for format changes . Will it cover all
> needs_modeset cases?
>
> OR do we also need to set planes_changed when
> drm_atomic_crtc_needs_modeset()?
>
> Unless I am missing something, I think we have to otherwise sspp
> reallocation wont happen in modeset cases.
I was depending on the planes being included in the state by the client.
I don't think we really care about the modeset per se. We care about
plane size changes. And changing the size means that the plane is
included into the commit.
>
> Overall, mainly we want to make sure SSPPs are re-assigned when:
>
0) plane size changes
> 1) format changes (RGB to YUV and vice-versa)
> 2) Any modesets
No
> 3) Any disable/enable without modeset like connectors changed as SSPPs are
> changing outputs there.
Absolutely no, the logic should be the same as active vs enabled for
CRTCs. Realloc resources only if the plane itself gets disabled or
enabled. In all other cases the set of SSPP blocks should stay
untouched.
>
> If we are covered for all these, let me know.
>
> > +
> > 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 15679dd50c66..70757d876cc3 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;
> > +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);
> > @@ -814,8 +817,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 935ff6fd172c..479d4c172290 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
> > @@ -54,6 +54,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;
> > @@ -128,6 +130,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];
> > };
>
> This is the part which now looks odd and can be managed with rebase I guess.
>
> Are you planning to pull in the move resource allocation to crtc_id changes
> first before this part? IOW, rebase this change on top of that?
No. I do not. If you remember, several revisions ago the enc_id ->
crtc_id was a part of the series, but we both agreed to drop it since it
was not required for virtual planes. As such, I plan to land this one
first (yes, having some of the resources tracked basing on enc_id and
SSPP is tracked basing on crtc_id).
>
> That will look clean because if this goes in first now, the crtc_id
> allocation changes will need to be rebased which I dont know who will do now
> as Jessica is OOO.
My plan is to pull this first and then pull patches 3-12 from the CWB
series. I do not expect significant conflicts there.
>
> > 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 5e230391fabc..125db3803cf5 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > @@ -878,7 +878,7 @@ static int dpu_plane_atomic_check_nosspp(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);
> > @@ -1001,8 +1001,13 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> > 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 (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_nosspp(plane, new_plane_state, crtc_state);
> > if (ret)
> > @@ -1019,6 +1024,112 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> > return dpu_plane_atomic_check_sspp(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 drm_plane_state *old_plane_state =
> > + drm_atomic_get_old_plane_state(state, plane);
> > + struct dpu_plane_state *pstate = to_dpu_plane_state(plane_state);
> > + struct drm_crtc_state *crtc_state;
> > + int ret;
> > +
> > + if (plane_state->crtc)
> > + crtc_state = drm_atomic_get_new_crtc_state(state,
> > + plane_state->crtc);
> > +
> > + ret = dpu_plane_atomic_check_nosspp(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;
> > + }
> > +
> > + /* force resource reallocation if the format of FB has changed */
> > + if (!old_plane_state || !old_plane_state->fb ||
> > + msm_framebuffer_format(old_plane_state->fb) !=
> > + msm_framebuffer_format(plane_state->fb))
> > + crtc_state->planes_changed = true;
> > +
> > + 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 msm_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 = msm_framebuffer_format(plane_state->fb);
> > + reqs.yuv = MSM_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_sspp(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 msm_format *format =
> > @@ -1331,12 +1442,15 @@ 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);
> > @@ -1429,31 +1543,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,
> > @@ -1479,7 +1591,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,
> > @@ -1487,10 +1599,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 31ee8b55c4dd..6d310bd9db30 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> > @@ -78,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
> > @@ -94,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..feeef9d31653 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> > @@ -694,6 +694,74 @@ int dpu_rm_reserve(
> > return ret;
> > }
> > +static struct dpu_hw_sspp *dpu_rm_try_sspp(struct dpu_rm *rm,
> > + struct dpu_global_state *global_state,
> > + struct drm_crtc *crtc,
> > + struct dpu_rm_sspp_requirements *reqs,
> > + unsigned int type)
> > +{
> > + uint32_t crtc_id = crtc->base.id;
> > + struct dpu_hw_sspp *hw_sspp;
> > + int i;
> > +
> > + 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];
> > +
> > + if (hw_sspp->cap->type != type)
> > + continue;
> > +
> > + if (reqs->scale && !hw_sspp->cap->sblk->scaler_blk.len)
> > + continue;
>
> We are already requesting a relevant SSPP when scale is needed so is this
> needed?
(here and below): yes, it is necessary for platforms like QCM2290, which
have ViG blocks, but no support for scaling.
>
> > +
> > + // TODO: QSEED2 and RGB scalers are not yet supported
> > + if (reqs->scale && !hw_sspp->ops.setup_scaler)
> > + continue;
> > +
>
> same here
We do not support QSEED2 setup, so it scaling is not possible on QSEED2
platforms even on ViG layers.
>
> > + if (reqs->yuv && !hw_sspp->cap->sblk->csc_blk.len)
> > + continue;
>
> same here
> > +
> > + if (reqs->rot90 && !(hw_sspp->cap->features & DPU_SSPP_INLINE_ROTATION))
> > + continue;
> > +
> > + global_state->sspp_to_crtc_id[i] = crtc_id;
> > +
> > + return rm->hw_sspp[i];
> > + }
> > +
> > + return NULL;
> > +}
> > +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)
> > +{
> > + struct dpu_hw_sspp *hw_sspp = NULL;
> > +
> > + if (!reqs->scale && !reqs->yuv)
> > + hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_DMA);
> > + if (!hw_sspp && reqs->scale)
> > + hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_RGB);
>
> I dont recollect whether RGB SSPPs supported scaling, if you have any source
> or link for this, that would help me for sure.
I have to dig further into the old fbdev driver. It looks like
mdss_mdp_qseed2_setup() is getting called for all plane types on the
corresponding hardware, but then it rejects scaling only for DMA and
CURSOR planes, which means that RGB planes should get the scaler setup.
For now this is from the SDE driver from 4.4:
* @SDE_SSPP_SCALER_RGB, RGB Scaler, supported by RGB pipes
> But even otherwise, I dont see any chipset in the catalog setting this SSPP
> type, so do we need to add this case?
Yes, we do. MSM8996 / MSM8937 / MSM8917 / MSM8953 use RGB planes.
>
> Overall, I am happier with this version which elimiates the hweight.
>
> > + if (!hw_sspp)
> > + hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_VIG);
> > +
> > + return hw_sspp;
> > +}
> > +
> > +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..6edff89fe83a 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,27 @@ 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
> > + */
> > +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] 30+ messages in thread
* Re: [PATCH v6 7/9] drm/msm/dpu: add support for virtual planes
2024-10-30 10:48 ` Dmitry Baryshkov
@ 2024-10-30 19:26 ` Abhinav Kumar
2024-10-31 15:11 ` Dmitry Baryshkov
0 siblings, 1 reply; 30+ messages in thread
From: Abhinav Kumar @ 2024-10-30 19:26 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Rob Clark, Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
linux-arm-msm, dri-devel, freedreno, linux-kernel
On 10/30/2024 3:48 AM, Dmitry Baryshkov wrote:
> On Tue, Oct 29, 2024 at 02:30:12PM -0700, Abhinav Kumar wrote:
>>
>>
>> On 10/24/2024 5:20 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.
>>>
>>> As the planes are attached to the CRTC and not the encoder, the SSPP
>>> blocks are also allocated per CRTC ID (all other resources are currently
>>> allocated per encoder ID). This also matches the hardware requirement,
>>> where both rectangles of a single SSPP can only be used with the LM
>>> pair.
>>>
>>> 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 | 237 ++++++++++++++++++++++++++----
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 16 ++
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 68 +++++++++
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 27 ++++
>>> 7 files changed, 383 insertions(+), 29 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>> index 58595dcc3889..a7eea094aa14 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>> @@ -1166,6 +1166,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)
>>> {
>>> @@ -1181,6 +1224,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;
>>> + }
>>
>> planes_changed is set only for format changes . Will it cover all
>> needs_modeset cases?
>>
>> OR do we also need to set planes_changed when
>> drm_atomic_crtc_needs_modeset()?
>>
>> Unless I am missing something, I think we have to otherwise sspp
>> reallocation wont happen in modeset cases.
>
> I was depending on the planes being included in the state by the client.
> I don't think we really care about the modeset per se. We care about
> plane size changes. And changing the size means that the plane is
> included into the commit.
>
The global state mapping for SSPPs has to be cleared across modesets
IMO. This is no different from us calling dpu_rm_release() today in
dpu_encoder_virt_atomic_check(). I just am not sure whether
planes_changed will cover all modeset conditions.
Were you able to confirm whether the mapping gets cleared across
hotplugs or suspend/resumes? If so, it would confirm whether
planes_changed covers these aspects. Although, I think clearing should
be more explicit.
Another option could be for you to call dpu_rm_release_all_sspp() in
dpu_crtc_disable(). So that across a disable and enable we have a clear
mapping table. WDYT?
>>
>> Overall, mainly we want to make sure SSPPs are re-assigned when:
>>
>
> 0) plane size changes
> >> 1) format changes (RGB to YUV and vice-versa)
>> 2) Any modesets
>
> No
I am not able to follow why this is different from any global state
mapping of other HW blocks that we do across modesets.
>
>> 3) Any disable/enable without modeset like connectors changed as SSPPs are
>> changing outputs there.
>
> Absolutely no, the logic should be the same as active vs enabled for
> CRTCs. Realloc resources only if the plane itself gets disabled or
> enabled. In all other cases the set of SSPP blocks should stay
> untouched.
>
I am going to re-visit this later perhaps but if we incorporate my above
suggestion of clearing the mapping in disable() I will be partially
satisfied.
>>
>> If we are covered for all these, let me know.
>>
>>> +
>>> 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 15679dd50c66..70757d876cc3 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;
>>> +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);
>>> @@ -814,8 +817,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 935ff6fd172c..479d4c172290 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
>>> @@ -54,6 +54,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;
>>> @@ -128,6 +130,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];
>>> };
>>
>> This is the part which now looks odd and can be managed with rebase I guess.
>>
>> Are you planning to pull in the move resource allocation to crtc_id changes
>> first before this part? IOW, rebase this change on top of that?
>
> No. I do not. If you remember, several revisions ago the enc_id ->
> crtc_id was a part of the series, but we both agreed to drop it since it
> was not required for virtual planes. As such, I plan to land this one
> first (yes, having some of the resources tracked basing on enc_id and
> SSPP is tracked basing on crtc_id).
>
Yes, I am not asking whether you will be absorbing those changes into
this series. Even I would not suggest doing that.
I was asking whether you will merge the crtc_id based tracking first and
then apply this on top of that and not the other way around.
Because with this specific line I am certain it will conflict as both
the series touch struct dpu_global_state.
>>
>> That will look clean because if this goes in first now, the crtc_id
>> allocation changes will need to be rebased which I dont know who will do now
>> as Jessica is OOO.
>
> My plan is to pull this first and then pull patches 3-12 from the CWB
> series. I do not expect significant conflicts there.
>
Please take a look at the part which touches struct dpu_global_state.
>>
>>> 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 5e230391fabc..125db3803cf5 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>> @@ -878,7 +878,7 @@ static int dpu_plane_atomic_check_nosspp(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);
>>> @@ -1001,8 +1001,13 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
>>> 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 (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_nosspp(plane, new_plane_state, crtc_state);
>>> if (ret)
>>> @@ -1019,6 +1024,112 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
>>> return dpu_plane_atomic_check_sspp(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 drm_plane_state *old_plane_state =
>>> + drm_atomic_get_old_plane_state(state, plane);
>>> + struct dpu_plane_state *pstate = to_dpu_plane_state(plane_state);
>>> + struct drm_crtc_state *crtc_state;
>>> + int ret;
>>> +
>>> + if (plane_state->crtc)
>>> + crtc_state = drm_atomic_get_new_crtc_state(state,
>>> + plane_state->crtc);
>>> +
>>> + ret = dpu_plane_atomic_check_nosspp(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;
>>> + }
>>> +
>>> + /* force resource reallocation if the format of FB has changed */
>>> + if (!old_plane_state || !old_plane_state->fb ||
>>> + msm_framebuffer_format(old_plane_state->fb) !=
>>> + msm_framebuffer_format(plane_state->fb))
>>> + crtc_state->planes_changed = true;
>>> +
>>> + 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 msm_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 = msm_framebuffer_format(plane_state->fb);
>>> + reqs.yuv = MSM_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_sspp(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 msm_format *format =
>>> @@ -1331,12 +1442,15 @@ 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);
>>> @@ -1429,31 +1543,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,
>>> @@ -1479,7 +1591,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,
>>> @@ -1487,10 +1599,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 31ee8b55c4dd..6d310bd9db30 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>>> @@ -78,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
>>> @@ -94,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..feeef9d31653 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>> @@ -694,6 +694,74 @@ int dpu_rm_reserve(
>>> return ret;
>>> }
>>> +static struct dpu_hw_sspp *dpu_rm_try_sspp(struct dpu_rm *rm,
>>> + struct dpu_global_state *global_state,
>>> + struct drm_crtc *crtc,
>>> + struct dpu_rm_sspp_requirements *reqs,
>>> + unsigned int type)
>>> +{
>>> + uint32_t crtc_id = crtc->base.id;
>>> + struct dpu_hw_sspp *hw_sspp;
>>> + int i;
>>> +
>>> + 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];
>>> +
>>> + if (hw_sspp->cap->type != type)
>>> + continue;
>>> +
>>> + if (reqs->scale && !hw_sspp->cap->sblk->scaler_blk.len)
>>> + continue;
>>
>> We are already requesting a relevant SSPP when scale is needed so is this
>> needed?
>
> (here and below): yes, it is necessary for platforms like QCM2290, which
> have ViG blocks, but no support for scaling.
>
Ok understood. Ack.
>>
>>> +
>>> + // TODO: QSEED2 and RGB scalers are not yet supported
>>> + if (reqs->scale && !hw_sspp->ops.setup_scaler)
>>> + continue;
>>> +
>>
>> same here
>
> We do not support QSEED2 setup, so it scaling is not possible on QSEED2
> platforms even on ViG layers.
>
Ack. My memory seems a bit weak on the older platforms. But I trust your
judgement with this one :)
>>
>>> + if (reqs->yuv && !hw_sspp->cap->sblk->csc_blk.len)
>>> + continue;
>>
>> same here
>>> +
>>> + if (reqs->rot90 && !(hw_sspp->cap->features & DPU_SSPP_INLINE_ROTATION))
>>> + continue;
>>> +
>>> + global_state->sspp_to_crtc_id[i] = crtc_id;
>>> +
>>> + return rm->hw_sspp[i];
>>> + }
>>> +
>>> + return NULL;
>>> +}
>>> +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)
>>> +{
>>> + struct dpu_hw_sspp *hw_sspp = NULL;
>>> +
>>> + if (!reqs->scale && !reqs->yuv)
>>> + hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_DMA);
>>> + if (!hw_sspp && reqs->scale)
>>> + hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_RGB);
>>
>> I dont recollect whether RGB SSPPs supported scaling, if you have any source
>> or link for this, that would help me for sure.
>
> I have to dig further into the old fbdev driver. It looks like
> mdss_mdp_qseed2_setup() is getting called for all plane types on the
> corresponding hardware, but then it rejects scaling only for DMA and
> CURSOR planes, which means that RGB planes should get the scaler setup.
>
> For now this is from the SDE driver from 4.4:
>
> * @SDE_SSPP_SCALER_RGB, RGB Scaler, supported by RGB pipes
>
>> But even otherwise, I dont see any chipset in the catalog setting this SSPP
>> type, so do we need to add this case?
>
> Yes, we do. MSM8996 / MSM8937 / MSM8917 / MSM8953 use RGB planes.
>
Yes those chipsets do have RGB SSPP. My question was whether they have
migrated to dpu and thats why I wanted to know whether we want to
include RGB SSPP handling.
I do not even see them in msm_mdp5_dpu_migration.
>>
>> Overall, I am happier with this version which elimiates the hweight.
>>
>>> + if (!hw_sspp)
>>> + hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_VIG);
>>> +
>>> + return hw_sspp;
>>> +}
>>> +
>>> +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..6edff89fe83a 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,27 @@ 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
>>> + */
>>> +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] 30+ messages in thread
* Re: [PATCH v6 7/9] drm/msm/dpu: add support for virtual planes
2024-10-30 19:26 ` Abhinav Kumar
@ 2024-10-31 15:11 ` Dmitry Baryshkov
2024-10-31 15:17 ` Dmitry Baryshkov
2024-10-31 20:06 ` Abhinav Kumar
0 siblings, 2 replies; 30+ messages in thread
From: Dmitry Baryshkov @ 2024-10-31 15:11 UTC (permalink / raw)
To: Abhinav Kumar
Cc: Rob Clark, Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
linux-arm-msm, dri-devel, freedreno, linux-kernel
Hi Abhinav,
On Wed, 30 Oct 2024 at 21:26, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>
>
>
> On 10/30/2024 3:48 AM, Dmitry Baryshkov wrote:
> > On Tue, Oct 29, 2024 at 02:30:12PM -0700, Abhinav Kumar wrote:
> >>
> >>
> >> On 10/24/2024 5:20 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.
> >>>
> >>> As the planes are attached to the CRTC and not the encoder, the SSPP
> >>> blocks are also allocated per CRTC ID (all other resources are currently
> >>> allocated per encoder ID). This also matches the hardware requirement,
> >>> where both rectangles of a single SSPP can only be used with the LM
> >>> pair.
> >>>
> >>> 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 | 237 ++++++++++++++++++++++++++----
> >>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 16 ++
> >>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 68 +++++++++
> >>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 27 ++++
> >>> 7 files changed, 383 insertions(+), 29 deletions(-)
> >>>
> >>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> >>> index 58595dcc3889..a7eea094aa14 100644
> >>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> >>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> >>> @@ -1166,6 +1166,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)
> >>> {
> >>> @@ -1181,6 +1224,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;
> >>> + }
> >>
> >> planes_changed is set only for format changes . Will it cover all
> >> needs_modeset cases?
> >>
> >> OR do we also need to set planes_changed when
> >> drm_atomic_crtc_needs_modeset()?
> >>
> >> Unless I am missing something, I think we have to otherwise sspp
> >> reallocation wont happen in modeset cases.
> >
> > I was depending on the planes being included in the state by the client.
> > I don't think we really care about the modeset per se. We care about
> > plane size changes. And changing the size means that the plane is
> > included into the commit.
> >
>
> The global state mapping for SSPPs has to be cleared across modesets
> IMO. This is no different from us calling dpu_rm_release() today in
> dpu_encoder_virt_atomic_check(). I just am not sure whether
> planes_changed will cover all modeset conditions.
We clear other resources, because they depend on the CRTC resolution.
Planes do not. Well, not until the quadpipe is in play.
SSPPs (currently) should be reallocated only if the _plane_'s
resolution change. If we have a modeset which involves CRTC resolution
change, but not the plane's size change, there is no need to
reallocate SSPPs.
>
> Were you able to confirm whether the mapping gets cleared across
> hotplugs or suspend/resumes? If so, it would confirm whether
> planes_changed covers these aspects. Although, I think clearing should
> be more explicit.
I will check that tomorrow.
> Another option could be for you to call dpu_rm_release_all_sspp() in
> dpu_crtc_disable(). So that across a disable and enable we have a clear
> mapping table. WDYT?
Absolutely no. The RM state should only be changed when other object's
state change - in atomic_check(). After that it is mostly r/o.
enabling/disabling the resource shouldn't change resource assignment
at all.
>
> >>
> >> Overall, mainly we want to make sure SSPPs are re-assigned when:
> >>
> >
> > 0) plane size changes
> > >> 1) format changes (RGB to YUV and vice-versa)
> >> 2) Any modesets
> >
> > No
>
> I am not able to follow why this is different from any global state
> mapping of other HW blocks that we do across modesets.
DIfferent lifecycle requirements, I'd say.
>
> >
> >> 3) Any disable/enable without modeset like connectors changed as SSPPs are
> >> changing outputs there.
> >
> > Absolutely no, the logic should be the same as active vs enabled for
> > CRTCs. Realloc resources only if the plane itself gets disabled or
> > enabled. In all other cases the set of SSPP blocks should stay
> > untouched.
> >
>
> I am going to re-visit this later perhaps but if we incorporate my above
> suggestion of clearing the mapping in disable() I will be partially
> satisfied.
No, resource mapping can not be cleaned in disable(). We do not do
that for any other resource kind.
>
> >>
> >> If we are covered for all these, let me know.
> >>
> >>> +
> >>> 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 15679dd50c66..70757d876cc3 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;
> >>> +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);
> >>> @@ -814,8 +817,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 935ff6fd172c..479d4c172290 100644
> >>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
> >>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
> >>> @@ -54,6 +54,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;
> >>> @@ -128,6 +130,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];
> >>> };
> >>
> >> This is the part which now looks odd and can be managed with rebase I guess.
> >>
> >> Are you planning to pull in the move resource allocation to crtc_id changes
> >> first before this part? IOW, rebase this change on top of that?
> >
> > No. I do not. If you remember, several revisions ago the enc_id ->
> > crtc_id was a part of the series, but we both agreed to drop it since it
> > was not required for virtual planes. As such, I plan to land this one
> > first (yes, having some of the resources tracked basing on enc_id and
> > SSPP is tracked basing on crtc_id).
> >
>
> Yes, I am not asking whether you will be absorbing those changes into
> this series. Even I would not suggest doing that.
>
> I was asking whether you will merge the crtc_id based tracking first and
> then apply this on top of that and not the other way around.
>
> Because with this specific line I am certain it will conflict as both
> the series touch struct dpu_global_state.
They touch different parts of it. So I'd prefer to land this one first
and then land using crtc_id for mapping.
>
> >>
> >> That will look clean because if this goes in first now, the crtc_id
> >> allocation changes will need to be rebased which I dont know who will do now
> >> as Jessica is OOO.
> >
> > My plan is to pull this first and then pull patches 3-12 from the CWB
> > series. I do not expect significant conflicts there.
> >
>
> Please take a look at the part which touches struct dpu_global_state.
>
> >>
> >>> 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 5e230391fabc..125db3803cf5 100644
> >>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> >>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> >>> @@ -878,7 +878,7 @@ static int dpu_plane_atomic_check_nosspp(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);
> >>> @@ -1001,8 +1001,13 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> >>> 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 (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_nosspp(plane, new_plane_state, crtc_state);
> >>> if (ret)
> >>> @@ -1019,6 +1024,112 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> >>> return dpu_plane_atomic_check_sspp(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 drm_plane_state *old_plane_state =
> >>> + drm_atomic_get_old_plane_state(state, plane);
> >>> + struct dpu_plane_state *pstate = to_dpu_plane_state(plane_state);
> >>> + struct drm_crtc_state *crtc_state;
> >>> + int ret;
> >>> +
> >>> + if (plane_state->crtc)
> >>> + crtc_state = drm_atomic_get_new_crtc_state(state,
> >>> + plane_state->crtc);
> >>> +
> >>> + ret = dpu_plane_atomic_check_nosspp(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;
> >>> + }
> >>> +
> >>> + /* force resource reallocation if the format of FB has changed */
> >>> + if (!old_plane_state || !old_plane_state->fb ||
> >>> + msm_framebuffer_format(old_plane_state->fb) !=
> >>> + msm_framebuffer_format(plane_state->fb))
> >>> + crtc_state->planes_changed = true;
> >>> +
> >>> + 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 msm_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 = msm_framebuffer_format(plane_state->fb);
> >>> + reqs.yuv = MSM_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_sspp(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 msm_format *format =
> >>> @@ -1331,12 +1442,15 @@ 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);
> >>> @@ -1429,31 +1543,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,
> >>> @@ -1479,7 +1591,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,
> >>> @@ -1487,10 +1599,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 31ee8b55c4dd..6d310bd9db30 100644
> >>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> >>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> >>> @@ -78,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
> >>> @@ -94,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..feeef9d31653 100644
> >>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> >>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> >>> @@ -694,6 +694,74 @@ int dpu_rm_reserve(
> >>> return ret;
> >>> }
> >>> +static struct dpu_hw_sspp *dpu_rm_try_sspp(struct dpu_rm *rm,
> >>> + struct dpu_global_state *global_state,
> >>> + struct drm_crtc *crtc,
> >>> + struct dpu_rm_sspp_requirements *reqs,
> >>> + unsigned int type)
> >>> +{
> >>> + uint32_t crtc_id = crtc->base.id;
> >>> + struct dpu_hw_sspp *hw_sspp;
> >>> + int i;
> >>> +
> >>> + 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];
> >>> +
> >>> + if (hw_sspp->cap->type != type)
> >>> + continue;
> >>> +
> >>> + if (reqs->scale && !hw_sspp->cap->sblk->scaler_blk.len)
> >>> + continue;
> >>
> >> We are already requesting a relevant SSPP when scale is needed so is this
> >> needed?
> >
> > (here and below): yes, it is necessary for platforms like QCM2290, which
> > have ViG blocks, but no support for scaling.
> >
>
> Ok understood. Ack.
>
> >>
> >>> +
> >>> + // TODO: QSEED2 and RGB scalers are not yet supported
> >>> + if (reqs->scale && !hw_sspp->ops.setup_scaler)
> >>> + continue;
> >>> +
> >>
> >> same here
> >
> > We do not support QSEED2 setup, so it scaling is not possible on QSEED2
> > platforms even on ViG layers.
> >
>
> Ack. My memory seems a bit weak on the older platforms. But I trust your
> judgement with this one :)
>
>
> >>
> >>> + if (reqs->yuv && !hw_sspp->cap->sblk->csc_blk.len)
> >>> + continue;
> >>
> >> same here
> >>> +
> >>> + if (reqs->rot90 && !(hw_sspp->cap->features & DPU_SSPP_INLINE_ROTATION))
> >>> + continue;
> >>> +
> >>> + global_state->sspp_to_crtc_id[i] = crtc_id;
> >>> +
> >>> + return rm->hw_sspp[i];
> >>> + }
> >>> +
> >>> + return NULL;
> >>> +}
> >>> +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)
> >>> +{
> >>> + struct dpu_hw_sspp *hw_sspp = NULL;
> >>> +
> >>> + if (!reqs->scale && !reqs->yuv)
> >>> + hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_DMA);
> >>> + if (!hw_sspp && reqs->scale)
> >>> + hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_RGB);
> >>
> >> I dont recollect whether RGB SSPPs supported scaling, if you have any source
> >> or link for this, that would help me for sure.
> >
> > I have to dig further into the old fbdev driver. It looks like
> > mdss_mdp_qseed2_setup() is getting called for all plane types on the
> > corresponding hardware, but then it rejects scaling only for DMA and
> > CURSOR planes, which means that RGB planes should get the scaler setup.
> >
> > For now this is from the SDE driver from 4.4:
> >
> > * @SDE_SSPP_SCALER_RGB, RGB Scaler, supported by RGB pipes
> >
> >> But even otherwise, I dont see any chipset in the catalog setting this SSPP
> >> type, so do we need to add this case?
> >
> > Yes, we do. MSM8996 / MSM8937 / MSM8917 / MSM8953 use RGB planes.
> >
>
> Yes those chipsets do have RGB SSPP. My question was whether they have
> migrated to dpu and thats why I wanted to know whether we want to
> include RGB SSPP handling.
>
> I do not even see them in msm_mdp5_dpu_migration.
Ugh, it's a bug then, I'll push a fix.
>
>
> >>
> >> Overall, I am happier with this version which elimiates the hweight.
> >>
> >>> + if (!hw_sspp)
> >>> + hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_VIG);
> >>> +
> >>> + return hw_sspp;
> >>> +}
> >>> +
> >>> +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..6edff89fe83a 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,27 @@ 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
> >>> + */
> >>> +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] 30+ messages in thread
* Re: [PATCH v6 7/9] drm/msm/dpu: add support for virtual planes
2024-10-31 15:11 ` Dmitry Baryshkov
@ 2024-10-31 15:17 ` Dmitry Baryshkov
2024-10-31 20:06 ` Abhinav Kumar
1 sibling, 0 replies; 30+ messages in thread
From: Dmitry Baryshkov @ 2024-10-31 15:17 UTC (permalink / raw)
To: Abhinav Kumar
Cc: Rob Clark, Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
linux-arm-msm, dri-devel, freedreno, linux-kernel
On Thu, 31 Oct 2024 at 17:11, Dmitry Baryshkov
<dmitry.baryshkov@linaro.org> wrote:
>
> Hi Abhinav,
>
> On Wed, 30 Oct 2024 at 21:26, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
> > On 10/30/2024 3:48 AM, Dmitry Baryshkov wrote:
> > > On Tue, Oct 29, 2024 at 02:30:12PM -0700, Abhinav Kumar wrote:
> > >> On 10/24/2024 5:20 PM, Dmitry Baryshkov wrote:
> > >>> + if (reqs->yuv && !hw_sspp->cap->sblk->csc_blk.len)
> > >>> + continue;
> > >>
> > >> same here
> > >>> +
> > >>> + if (reqs->rot90 && !(hw_sspp->cap->features & DPU_SSPP_INLINE_ROTATION))
> > >>> + continue;
> > >>> +
> > >>> + global_state->sspp_to_crtc_id[i] = crtc_id;
> > >>> +
> > >>> + return rm->hw_sspp[i];
> > >>> + }
> > >>> +
> > >>> + return NULL;
> > >>> +}
> > >>> +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)
> > >>> +{
> > >>> + struct dpu_hw_sspp *hw_sspp = NULL;
> > >>> +
> > >>> + if (!reqs->scale && !reqs->yuv)
> > >>> + hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_DMA);
> > >>> + if (!hw_sspp && reqs->scale)
> > >>> + hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_RGB);
> > >>
> > >> I dont recollect whether RGB SSPPs supported scaling, if you have any source
> > >> or link for this, that would help me for sure.
> > >
> > > I have to dig further into the old fbdev driver. It looks like
> > > mdss_mdp_qseed2_setup() is getting called for all plane types on the
> > > corresponding hardware, but then it rejects scaling only for DMA and
> > > CURSOR planes, which means that RGB planes should get the scaler setup.
> > >
> > > For now this is from the SDE driver from 4.4:
> > >
> > > * @SDE_SSPP_SCALER_RGB, RGB Scaler, supported by RGB pipes
> > >
> > >> But even otherwise, I dont see any chipset in the catalog setting this SSPP
> > >> type, so do we need to add this case?
> > >
> > > Yes, we do. MSM8996 / MSM8937 / MSM8917 / MSM8953 use RGB planes.
> > >
> >
> > Yes those chipsets do have RGB SSPP. My question was whether they have
> > migrated to dpu and thats why I wanted to know whether we want to
> > include RGB SSPP handling.
> >
> > I do not even see them in msm_mdp5_dpu_migration.
>
> Ugh, it's a bug then, I'll push a fix.
Ok, this is very surprising:
static const char *const msm_mdp5_dpu_migration[] = {
"qcom,msm8917-mdp5",
"qcom,msm8937-mdp5",
"qcom,msm8953-mdp5",
"qcom,msm8996-mdp5",
"qcom,sdm630-mdp5",
"qcom,sdm660-mdp5",
NULL,
};
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v6 7/9] drm/msm/dpu: add support for virtual planes
2024-10-31 15:11 ` Dmitry Baryshkov
2024-10-31 15:17 ` Dmitry Baryshkov
@ 2024-10-31 20:06 ` Abhinav Kumar
2024-10-31 21:03 ` Dmitry Baryshkov
1 sibling, 1 reply; 30+ messages in thread
From: Abhinav Kumar @ 2024-10-31 20:06 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Rob Clark, Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
linux-arm-msm, dri-devel, freedreno, linux-kernel
On 10/31/2024 8:11 AM, Dmitry Baryshkov wrote:
> Hi Abhinav,
>
> On Wed, 30 Oct 2024 at 21:26, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>>
>>
>>
>> On 10/30/2024 3:48 AM, Dmitry Baryshkov wrote:
>>> On Tue, Oct 29, 2024 at 02:30:12PM -0700, Abhinav Kumar wrote:
>>>>
>>>>
>>>> On 10/24/2024 5:20 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.
>>>>>
>>>>> As the planes are attached to the CRTC and not the encoder, the SSPP
>>>>> blocks are also allocated per CRTC ID (all other resources are currently
>>>>> allocated per encoder ID). This also matches the hardware requirement,
>>>>> where both rectangles of a single SSPP can only be used with the LM
>>>>> pair.
>>>>>
>>>>> 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 | 237 ++++++++++++++++++++++++++----
>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 16 ++
>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 68 +++++++++
>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 27 ++++
>>>>> 7 files changed, 383 insertions(+), 29 deletions(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>> index 58595dcc3889..a7eea094aa14 100644
>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>> @@ -1166,6 +1166,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)
>>>>> {
>>>>> @@ -1181,6 +1224,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;
>>>>> + }
>>>>
>>>> planes_changed is set only for format changes . Will it cover all
>>>> needs_modeset cases?
>>>>
>>>> OR do we also need to set planes_changed when
>>>> drm_atomic_crtc_needs_modeset()?
>>>>
>>>> Unless I am missing something, I think we have to otherwise sspp
>>>> reallocation wont happen in modeset cases.
>>>
>>> I was depending on the planes being included in the state by the client.
>>> I don't think we really care about the modeset per se. We care about
>>> plane size changes. And changing the size means that the plane is
>>> included into the commit.
>>>
>>
>> The global state mapping for SSPPs has to be cleared across modesets
>> IMO. This is no different from us calling dpu_rm_release() today in
>> dpu_encoder_virt_atomic_check(). I just am not sure whether
>> planes_changed will cover all modeset conditions.
>
> We clear other resources, because they depend on the CRTC resolution.
> Planes do not. Well, not until the quadpipe is in play.
> SSPPs (currently) should be reallocated only if the _plane_'s
> resolution change. If we have a modeset which involves CRTC resolution
> change, but not the plane's size change, there is no need to
> reallocate SSPPs.
>
In dpu_encoder_helper_phys_cleanup(), the SSPPs attached to all LMs are
removed so clearing all the hardware. If the global state is still going
to retain the older configuration not reflecting this clear, it seems
incorrect to me. Thats why I was thinking of clearing all the SSPP
mapping in disable() or in the modeset prior to the disable as
technically thats being done in HW today anyway.
During the next atomic check, the planes in the crtc's current state
will get re-attached and programmed to the blend stages. So this
clearing of global state is reflecting the current state of the
corresponding hardware.
>>
>> Were you able to confirm whether the mapping gets cleared across
>> hotplugs or suspend/resumes? If so, it would confirm whether
>> planes_changed covers these aspects. Although, I think clearing should
>> be more explicit.
>
> I will check that tomorrow.
>
>> Another option could be for you to call dpu_rm_release_all_sspp() in
>> dpu_crtc_disable(). So that across a disable and enable we have a clear
>> mapping table. WDYT?
>
> Absolutely no. The RM state should only be changed when other object's
> state change - in atomic_check(). After that it is mostly r/o.
> enabling/disabling the resource shouldn't change resource assignment
> at all.
>
>>
>>>>
>>>> Overall, mainly we want to make sure SSPPs are re-assigned when:
>>>>
>>>
>>> 0) plane size changes
>>>>> 1) format changes (RGB to YUV and vice-versa)
>>>> 2) Any modesets
>>>
>>> No
>>
>> I am not able to follow why this is different from any global state
>> mapping of other HW blocks that we do across modesets.
>
> DIfferent lifecycle requirements, I'd say.
>
>>
>>>
>>>> 3) Any disable/enable without modeset like connectors changed as SSPPs are
>>>> changing outputs there.
>>>
>>> Absolutely no, the logic should be the same as active vs enabled for
>>> CRTCs. Realloc resources only if the plane itself gets disabled or
>>> enabled. In all other cases the set of SSPP blocks should stay
>>> untouched.
>>>
>>
>> I am going to re-visit this later perhaps but if we incorporate my above
>> suggestion of clearing the mapping in disable() I will be partially
>> satisfied.
>
> No, resource mapping can not be cleaned in disable(). We do not do
> that for any other resource kind.
>
That gets handled with the needs_modeset part today which is calling the
dpu_rm_release().
>>
>>>>
>>>> If we are covered for all these, let me know.
>>>>
>>>>> +
>>>>> 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 15679dd50c66..70757d876cc3 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;
>>>>> +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);
>>>>> @@ -814,8 +817,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 935ff6fd172c..479d4c172290 100644
>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
>>>>> @@ -54,6 +54,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;
>>>>> @@ -128,6 +130,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];
>>>>> };
>>>>
>>>> This is the part which now looks odd and can be managed with rebase I guess.
>>>>
>>>> Are you planning to pull in the move resource allocation to crtc_id changes
>>>> first before this part? IOW, rebase this change on top of that?
>>>
>>> No. I do not. If you remember, several revisions ago the enc_id ->
>>> crtc_id was a part of the series, but we both agreed to drop it since it
>>> was not required for virtual planes. As such, I plan to land this one
>>> first (yes, having some of the resources tracked basing on enc_id and
>>> SSPP is tracked basing on crtc_id).
>>>
>>
>> Yes, I am not asking whether you will be absorbing those changes into
>> this series. Even I would not suggest doing that.
>>
>> I was asking whether you will merge the crtc_id based tracking first and
>> then apply this on top of that and not the other way around.
>>
>> Because with this specific line I am certain it will conflict as both
>> the series touch struct dpu_global_state.
>
> They touch different parts of it. So I'd prefer to land this one first
> and then land using crtc_id for mapping.
>
I am okay to fixup any other issues which arise later on because we have
the modparam protection anyway but I think validating suspend/resume and
hotplug to ensure no black screens is required. If those two cases work
fine on your end, we can proceed.
>>
>>>>
>>>> That will look clean because if this goes in first now, the crtc_id
>>>> allocation changes will need to be rebased which I dont know who will do now
>>>> as Jessica is OOO.
>>>
>>> My plan is to pull this first and then pull patches 3-12 from the CWB
>>> series. I do not expect significant conflicts there.
>>>
>>
>> Please take a look at the part which touches struct dpu_global_state.
>>
>>>>
>>>>> 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 5e230391fabc..125db3803cf5 100644
>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
>>>>> @@ -878,7 +878,7 @@ static int dpu_plane_atomic_check_nosspp(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);
>>>>> @@ -1001,8 +1001,13 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
>>>>> 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 (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_nosspp(plane, new_plane_state, crtc_state);
>>>>> if (ret)
>>>>> @@ -1019,6 +1024,112 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
>>>>> return dpu_plane_atomic_check_sspp(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 drm_plane_state *old_plane_state =
>>>>> + drm_atomic_get_old_plane_state(state, plane);
>>>>> + struct dpu_plane_state *pstate = to_dpu_plane_state(plane_state);
>>>>> + struct drm_crtc_state *crtc_state;
>>>>> + int ret;
>>>>> +
>>>>> + if (plane_state->crtc)
>>>>> + crtc_state = drm_atomic_get_new_crtc_state(state,
>>>>> + plane_state->crtc);
>>>>> +
>>>>> + ret = dpu_plane_atomic_check_nosspp(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;
>>>>> + }
>>>>> +
>>>>> + /* force resource reallocation if the format of FB has changed */
>>>>> + if (!old_plane_state || !old_plane_state->fb ||
>>>>> + msm_framebuffer_format(old_plane_state->fb) !=
>>>>> + msm_framebuffer_format(plane_state->fb))
>>>>> + crtc_state->planes_changed = true;
>>>>> +
>>>>> + 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 msm_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 = msm_framebuffer_format(plane_state->fb);
>>>>> + reqs.yuv = MSM_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_sspp(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 msm_format *format =
>>>>> @@ -1331,12 +1442,15 @@ 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);
>>>>> @@ -1429,31 +1543,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,
>>>>> @@ -1479,7 +1591,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,
>>>>> @@ -1487,10 +1599,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 31ee8b55c4dd..6d310bd9db30 100644
>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
>>>>> @@ -78,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
>>>>> @@ -94,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..feeef9d31653 100644
>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
>>>>> @@ -694,6 +694,74 @@ int dpu_rm_reserve(
>>>>> return ret;
>>>>> }
>>>>> +static struct dpu_hw_sspp *dpu_rm_try_sspp(struct dpu_rm *rm,
>>>>> + struct dpu_global_state *global_state,
>>>>> + struct drm_crtc *crtc,
>>>>> + struct dpu_rm_sspp_requirements *reqs,
>>>>> + unsigned int type)
>>>>> +{
>>>>> + uint32_t crtc_id = crtc->base.id;
>>>>> + struct dpu_hw_sspp *hw_sspp;
>>>>> + int i;
>>>>> +
>>>>> + 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];
>>>>> +
>>>>> + if (hw_sspp->cap->type != type)
>>>>> + continue;
>>>>> +
>>>>> + if (reqs->scale && !hw_sspp->cap->sblk->scaler_blk.len)
>>>>> + continue;
>>>>
>>>> We are already requesting a relevant SSPP when scale is needed so is this
>>>> needed?
>>>
>>> (here and below): yes, it is necessary for platforms like QCM2290, which
>>> have ViG blocks, but no support for scaling.
>>>
>>
>> Ok understood. Ack.
>>
>>>>
>>>>> +
>>>>> + // TODO: QSEED2 and RGB scalers are not yet supported
>>>>> + if (reqs->scale && !hw_sspp->ops.setup_scaler)
>>>>> + continue;
>>>>> +
>>>>
>>>> same here
>>>
>>> We do not support QSEED2 setup, so it scaling is not possible on QSEED2
>>> platforms even on ViG layers.
>>>
>>
>> Ack. My memory seems a bit weak on the older platforms. But I trust your
>> judgement with this one :)
>>
>>
>>>>
>>>>> + if (reqs->yuv && !hw_sspp->cap->sblk->csc_blk.len)
>>>>> + continue;
>>>>
>>>> same here
>>>>> +
>>>>> + if (reqs->rot90 && !(hw_sspp->cap->features & DPU_SSPP_INLINE_ROTATION))
>>>>> + continue;
>>>>> +
>>>>> + global_state->sspp_to_crtc_id[i] = crtc_id;
>>>>> +
>>>>> + return rm->hw_sspp[i];
>>>>> + }
>>>>> +
>>>>> + return NULL;
>>>>> +}
>>>>> +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)
>>>>> +{
>>>>> + struct dpu_hw_sspp *hw_sspp = NULL;
>>>>> +
>>>>> + if (!reqs->scale && !reqs->yuv)
>>>>> + hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_DMA);
>>>>> + if (!hw_sspp && reqs->scale)
>>>>> + hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_RGB);
>>>>
>>>> I dont recollect whether RGB SSPPs supported scaling, if you have any source
>>>> or link for this, that would help me for sure.
>>>
>>> I have to dig further into the old fbdev driver. It looks like
>>> mdss_mdp_qseed2_setup() is getting called for all plane types on the
>>> corresponding hardware, but then it rejects scaling only for DMA and
>>> CURSOR planes, which means that RGB planes should get the scaler setup.
>>>
>>> For now this is from the SDE driver from 4.4:
>>>
>>> * @SDE_SSPP_SCALER_RGB, RGB Scaler, supported by RGB pipes
>>>
>>>> But even otherwise, I dont see any chipset in the catalog setting this SSPP
>>>> type, so do we need to add this case?
>>>
>>> Yes, we do. MSM8996 / MSM8937 / MSM8917 / MSM8953 use RGB planes.
>>>
>>
>> Yes those chipsets do have RGB SSPP. My question was whether they have
>> migrated to dpu and thats why I wanted to know whether we want to
>> include RGB SSPP handling.
>>
>> I do not even see them in msm_mdp5_dpu_migration.
>
> Ugh, it's a bug then, I'll push a fix.
>
Actually this was part of the 6.13 MR. My apologies, I was on linux-next
which was a week old.
Yes, I see this on the latest msm-next. I am fine with this part.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v6 7/9] drm/msm/dpu: add support for virtual planes
2024-10-31 20:06 ` Abhinav Kumar
@ 2024-10-31 21:03 ` Dmitry Baryshkov
2024-11-01 20:37 ` Abhinav Kumar
0 siblings, 1 reply; 30+ messages in thread
From: Dmitry Baryshkov @ 2024-10-31 21:03 UTC (permalink / raw)
To: Abhinav Kumar
Cc: Rob Clark, Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
linux-arm-msm, dri-devel, freedreno, linux-kernel
On Thu, Oct 31, 2024 at 01:06:34PM -0700, Abhinav Kumar wrote:
>
>
> On 10/31/2024 8:11 AM, Dmitry Baryshkov wrote:
> > Hi Abhinav,
> >
> > On Wed, 30 Oct 2024 at 21:26, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
> > >
> > >
> > >
> > > On 10/30/2024 3:48 AM, Dmitry Baryshkov wrote:
> > > > On Tue, Oct 29, 2024 at 02:30:12PM -0700, Abhinav Kumar wrote:
> > > > >
> > > > >
> > > > > On 10/24/2024 5:20 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.
> > > > > >
> > > > > > As the planes are attached to the CRTC and not the encoder, the SSPP
> > > > > > blocks are also allocated per CRTC ID (all other resources are currently
> > > > > > allocated per encoder ID). This also matches the hardware requirement,
> > > > > > where both rectangles of a single SSPP can only be used with the LM
> > > > > > pair.
> > > > > >
> > > > > > 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 | 237 ++++++++++++++++++++++++++----
> > > > > > drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 16 ++
> > > > > > drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 68 +++++++++
> > > > > > drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 27 ++++
> > > > > > 7 files changed, 383 insertions(+), 29 deletions(-)
> > > > > >
> > > > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > > > index 58595dcc3889..a7eea094aa14 100644
> > > > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > > > @@ -1166,6 +1166,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)
> > > > > > {
> > > > > > @@ -1181,6 +1224,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;
> > > > > > + }
> > > > >
> > > > > planes_changed is set only for format changes . Will it cover all
> > > > > needs_modeset cases?
> > > > >
> > > > > OR do we also need to set planes_changed when
> > > > > drm_atomic_crtc_needs_modeset()?
> > > > >
> > > > > Unless I am missing something, I think we have to otherwise sspp
> > > > > reallocation wont happen in modeset cases.
> > > >
> > > > I was depending on the planes being included in the state by the client.
> > > > I don't think we really care about the modeset per se. We care about
> > > > plane size changes. And changing the size means that the plane is
> > > > included into the commit.
> > > >
> > >
> > > The global state mapping for SSPPs has to be cleared across modesets
> > > IMO. This is no different from us calling dpu_rm_release() today in
> > > dpu_encoder_virt_atomic_check(). I just am not sure whether
> > > planes_changed will cover all modeset conditions.
> >
> > We clear other resources, because they depend on the CRTC resolution.
> > Planes do not. Well, not until the quadpipe is in play.
> > SSPPs (currently) should be reallocated only if the _plane_'s
> > resolution change. If we have a modeset which involves CRTC resolution
> > change, but not the plane's size change, there is no need to
> > reallocate SSPPs.
> >
>
> In dpu_encoder_helper_phys_cleanup(), the SSPPs attached to all LMs are
> removed so clearing all the hardware. If the global state is still going to
> retain the older configuration not reflecting this clear, it seems incorrect
> to me. Thats why I was thinking of clearing all the SSPP mapping in
> disable() or in the modeset prior to the disable as technically thats being
> done in HW today anyway.
>
> During the next atomic check, the planes in the crtc's current state will
> get re-attached and programmed to the blend stages. So this clearing of
> global state is reflecting the current state of the corresponding hardware.
The global state tracks resource allocation. If we clear the resources
in the disable() path, we have no way to know which SSPP blocks were
assigned to us in the corresponding enable() call path. There is no
guarantee that there will be an atomic_check() between disable() and
enable().
>
> > >
> > > Were you able to confirm whether the mapping gets cleared across
> > > hotplugs or suspend/resumes? If so, it would confirm whether
> > > planes_changed covers these aspects. Although, I think clearing should
> > > be more explicit.
> >
> > I will check that tomorrow.
> >
> > > Another option could be for you to call dpu_rm_release_all_sspp() in
> > > dpu_crtc_disable(). So that across a disable and enable we have a clear
> > > mapping table. WDYT?
> >
> > Absolutely no. The RM state should only be changed when other object's
> > state change - in atomic_check(). After that it is mostly r/o.
> > enabling/disabling the resource shouldn't change resource assignment
> > at all.
> >
> > >
> > > > >
> > > > > Overall, mainly we want to make sure SSPPs are re-assigned when:
> > > > >
> > > >
> > > > 0) plane size changes
> > > > > > 1) format changes (RGB to YUV and vice-versa)
> > > > > 2) Any modesets
> > > >
> > > > No
> > >
> > > I am not able to follow why this is different from any global state
> > > mapping of other HW blocks that we do across modesets.
> >
> > DIfferent lifecycle requirements, I'd say.
> >
> > >
> > > >
> > > > > 3) Any disable/enable without modeset like connectors changed as SSPPs are
> > > > > changing outputs there.
> > > >
> > > > Absolutely no, the logic should be the same as active vs enabled for
> > > > CRTCs. Realloc resources only if the plane itself gets disabled or
> > > > enabled. In all other cases the set of SSPP blocks should stay
> > > > untouched.
> > > >
> > >
> > > I am going to re-visit this later perhaps but if we incorporate my above
> > > suggestion of clearing the mapping in disable() I will be partially
> > > satisfied.
> >
> > No, resource mapping can not be cleaned in disable(). We do not do
> > that for any other resource kind.
> >
>
> That gets handled with the needs_modeset part today which is calling the
> dpu_rm_release().
In atomic_check() path, not in the disable() path.
>
> > >
> > > > >
> > > > > If we are covered for all these, let me know.
> > > > >
> > > > > > +
> > > > > > 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 15679dd50c66..70757d876cc3 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;
> > > > > > +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);
> > > > > > @@ -814,8 +817,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 935ff6fd172c..479d4c172290 100644
> > > > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
> > > > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
> > > > > > @@ -54,6 +54,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;
> > > > > > @@ -128,6 +130,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];
> > > > > > };
> > > > >
> > > > > This is the part which now looks odd and can be managed with rebase I guess.
> > > > >
> > > > > Are you planning to pull in the move resource allocation to crtc_id changes
> > > > > first before this part? IOW, rebase this change on top of that?
> > > >
> > > > No. I do not. If you remember, several revisions ago the enc_id ->
> > > > crtc_id was a part of the series, but we both agreed to drop it since it
> > > > was not required for virtual planes. As such, I plan to land this one
> > > > first (yes, having some of the resources tracked basing on enc_id and
> > > > SSPP is tracked basing on crtc_id).
> > > >
> > >
> > > Yes, I am not asking whether you will be absorbing those changes into
> > > this series. Even I would not suggest doing that.
> > >
> > > I was asking whether you will merge the crtc_id based tracking first and
> > > then apply this on top of that and not the other way around.
> > >
> > > Because with this specific line I am certain it will conflict as both
> > > the series touch struct dpu_global_state.
> >
> > They touch different parts of it. So I'd prefer to land this one first
> > and then land using crtc_id for mapping.
> >
>
> I am okay to fixup any other issues which arise later on because we have the
> modparam protection anyway but I think validating suspend/resume and hotplug
> to ensure no black screens is required. If those two cases work fine on your
> end, we can proceed.
I have been validating these changes with hotplug events, yes. I wasn't
checking the suspend/resume, but that's broken anyway, until we land
https://patchwork.freedesktop.org/patch/606931/?series=135908&rev=2
>
> > >
> > > > >
> > > > > That will look clean because if this goes in first now, the crtc_id
> > > > > allocation changes will need to be rebased which I dont know who will do now
> > > > > as Jessica is OOO.
> > > >
> > > > My plan is to pull this first and then pull patches 3-12 from the CWB
> > > > series. I do not expect significant conflicts there.
> > > >
> > >
> > > Please take a look at the part which touches struct dpu_global_state.
> > >
> > > > >
> > > > > > 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 5e230391fabc..125db3803cf5 100644
> > > > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> > > > > > @@ -878,7 +878,7 @@ static int dpu_plane_atomic_check_nosspp(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);
> > > > > > @@ -1001,8 +1001,13 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> > > > > > 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 (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_nosspp(plane, new_plane_state, crtc_state);
> > > > > > if (ret)
> > > > > > @@ -1019,6 +1024,112 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
> > > > > > return dpu_plane_atomic_check_sspp(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 drm_plane_state *old_plane_state =
> > > > > > + drm_atomic_get_old_plane_state(state, plane);
> > > > > > + struct dpu_plane_state *pstate = to_dpu_plane_state(plane_state);
> > > > > > + struct drm_crtc_state *crtc_state;
> > > > > > + int ret;
> > > > > > +
> > > > > > + if (plane_state->crtc)
> > > > > > + crtc_state = drm_atomic_get_new_crtc_state(state,
> > > > > > + plane_state->crtc);
> > > > > > +
> > > > > > + ret = dpu_plane_atomic_check_nosspp(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;
> > > > > > + }
> > > > > > +
> > > > > > + /* force resource reallocation if the format of FB has changed */
> > > > > > + if (!old_plane_state || !old_plane_state->fb ||
> > > > > > + msm_framebuffer_format(old_plane_state->fb) !=
> > > > > > + msm_framebuffer_format(plane_state->fb))
> > > > > > + crtc_state->planes_changed = true;
> > > > > > +
> > > > > > + 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 msm_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 = msm_framebuffer_format(plane_state->fb);
> > > > > > + reqs.yuv = MSM_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_sspp(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 msm_format *format =
> > > > > > @@ -1331,12 +1442,15 @@ 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);
> > > > > > @@ -1429,31 +1543,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,
> > > > > > @@ -1479,7 +1591,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,
> > > > > > @@ -1487,10 +1599,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 31ee8b55c4dd..6d310bd9db30 100644
> > > > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> > > > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> > > > > > @@ -78,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
> > > > > > @@ -94,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..feeef9d31653 100644
> > > > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> > > > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> > > > > > @@ -694,6 +694,74 @@ int dpu_rm_reserve(
> > > > > > return ret;
> > > > > > }
> > > > > > +static struct dpu_hw_sspp *dpu_rm_try_sspp(struct dpu_rm *rm,
> > > > > > + struct dpu_global_state *global_state,
> > > > > > + struct drm_crtc *crtc,
> > > > > > + struct dpu_rm_sspp_requirements *reqs,
> > > > > > + unsigned int type)
> > > > > > +{
> > > > > > + uint32_t crtc_id = crtc->base.id;
> > > > > > + struct dpu_hw_sspp *hw_sspp;
> > > > > > + int i;
> > > > > > +
> > > > > > + 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];
> > > > > > +
> > > > > > + if (hw_sspp->cap->type != type)
> > > > > > + continue;
> > > > > > +
> > > > > > + if (reqs->scale && !hw_sspp->cap->sblk->scaler_blk.len)
> > > > > > + continue;
> > > > >
> > > > > We are already requesting a relevant SSPP when scale is needed so is this
> > > > > needed?
> > > >
> > > > (here and below): yes, it is necessary for platforms like QCM2290, which
> > > > have ViG blocks, but no support for scaling.
> > > >
> > >
> > > Ok understood. Ack.
> > >
> > > > >
> > > > > > +
> > > > > > + // TODO: QSEED2 and RGB scalers are not yet supported
> > > > > > + if (reqs->scale && !hw_sspp->ops.setup_scaler)
> > > > > > + continue;
> > > > > > +
> > > > >
> > > > > same here
> > > >
> > > > We do not support QSEED2 setup, so it scaling is not possible on QSEED2
> > > > platforms even on ViG layers.
> > > >
> > >
> > > Ack. My memory seems a bit weak on the older platforms. But I trust your
> > > judgement with this one :)
> > >
> > >
> > > > >
> > > > > > + if (reqs->yuv && !hw_sspp->cap->sblk->csc_blk.len)
> > > > > > + continue;
> > > > >
> > > > > same here
> > > > > > +
> > > > > > + if (reqs->rot90 && !(hw_sspp->cap->features & DPU_SSPP_INLINE_ROTATION))
> > > > > > + continue;
> > > > > > +
> > > > > > + global_state->sspp_to_crtc_id[i] = crtc_id;
> > > > > > +
> > > > > > + return rm->hw_sspp[i];
> > > > > > + }
> > > > > > +
> > > > > > + return NULL;
> > > > > > +}
> > > > > > +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)
> > > > > > +{
> > > > > > + struct dpu_hw_sspp *hw_sspp = NULL;
> > > > > > +
> > > > > > + if (!reqs->scale && !reqs->yuv)
> > > > > > + hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_DMA);
> > > > > > + if (!hw_sspp && reqs->scale)
> > > > > > + hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_RGB);
> > > > >
> > > > > I dont recollect whether RGB SSPPs supported scaling, if you have any source
> > > > > or link for this, that would help me for sure.
> > > >
> > > > I have to dig further into the old fbdev driver. It looks like
> > > > mdss_mdp_qseed2_setup() is getting called for all plane types on the
> > > > corresponding hardware, but then it rejects scaling only for DMA and
> > > > CURSOR planes, which means that RGB planes should get the scaler setup.
> > > >
> > > > For now this is from the SDE driver from 4.4:
> > > >
> > > > * @SDE_SSPP_SCALER_RGB, RGB Scaler, supported by RGB pipes
> > > >
> > > > > But even otherwise, I dont see any chipset in the catalog setting this SSPP
> > > > > type, so do we need to add this case?
> > > >
> > > > Yes, we do. MSM8996 / MSM8937 / MSM8917 / MSM8953 use RGB planes.
> > > >
> > >
> > > Yes those chipsets do have RGB SSPP. My question was whether they have
> > > migrated to dpu and thats why I wanted to know whether we want to
> > > include RGB SSPP handling.
> > >
> > > I do not even see them in msm_mdp5_dpu_migration.
> >
> > Ugh, it's a bug then, I'll push a fix.
> >
>
> Actually this was part of the 6.13 MR. My apologies, I was on linux-next
> which was a week old.
>
> Yes, I see this on the latest msm-next. I am fine with this part.
No worries. I also didn't have source code in front of my eyes at that
moment.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v6 7/9] drm/msm/dpu: add support for virtual planes
2024-10-31 21:03 ` Dmitry Baryshkov
@ 2024-11-01 20:37 ` Abhinav Kumar
2024-11-01 20:53 ` Dmitry Baryshkov
0 siblings, 1 reply; 30+ messages in thread
From: Abhinav Kumar @ 2024-11-01 20:37 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Rob Clark, Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
linux-arm-msm, dri-devel, freedreno, linux-kernel
On 10/31/2024 2:03 PM, Dmitry Baryshkov wrote:
> On Thu, Oct 31, 2024 at 01:06:34PM -0700, Abhinav Kumar wrote:
>>
>>
>> On 10/31/2024 8:11 AM, Dmitry Baryshkov wrote:
>>> Hi Abhinav,
>>>
>>> On Wed, 30 Oct 2024 at 21:26, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>>>>
>>>>
>>>>
>>>> On 10/30/2024 3:48 AM, Dmitry Baryshkov wrote:
>>>>> On Tue, Oct 29, 2024 at 02:30:12PM -0700, Abhinav Kumar wrote:
>>>>>>
>>>>>>
>>>>>> On 10/24/2024 5:20 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.
>>>>>>>
>>>>>>> As the planes are attached to the CRTC and not the encoder, the SSPP
>>>>>>> blocks are also allocated per CRTC ID (all other resources are currently
>>>>>>> allocated per encoder ID). This also matches the hardware requirement,
>>>>>>> where both rectangles of a single SSPP can only be used with the LM
>>>>>>> pair.
>>>>>>>
>>>>>>> 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 | 237 ++++++++++++++++++++++++++----
>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 16 ++
>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 68 +++++++++
>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 27 ++++
>>>>>>> 7 files changed, 383 insertions(+), 29 deletions(-)
>>>>>>>
>>>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>>>> index 58595dcc3889..a7eea094aa14 100644
>>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>>>> @@ -1166,6 +1166,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)
>>>>>>> {
>>>>>>> @@ -1181,6 +1224,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;
>>>>>>> + }
>>>>>>
>>>>>> planes_changed is set only for format changes . Will it cover all
>>>>>> needs_modeset cases?
>>>>>>
>>>>>> OR do we also need to set planes_changed when
>>>>>> drm_atomic_crtc_needs_modeset()?
>>>>>>
>>>>>> Unless I am missing something, I think we have to otherwise sspp
>>>>>> reallocation wont happen in modeset cases.
>>>>>
>>>>> I was depending on the planes being included in the state by the client.
>>>>> I don't think we really care about the modeset per se. We care about
>>>>> plane size changes. And changing the size means that the plane is
>>>>> included into the commit.
>>>>>
>>>>
>>>> The global state mapping for SSPPs has to be cleared across modesets
>>>> IMO. This is no different from us calling dpu_rm_release() today in
>>>> dpu_encoder_virt_atomic_check(). I just am not sure whether
>>>> planes_changed will cover all modeset conditions.
>>>
>>> We clear other resources, because they depend on the CRTC resolution.
>>> Planes do not. Well, not until the quadpipe is in play.
>>> SSPPs (currently) should be reallocated only if the _plane_'s
>>> resolution change. If we have a modeset which involves CRTC resolution
>>> change, but not the plane's size change, there is no need to
>>> reallocate SSPPs.
>>>
>>
>> In dpu_encoder_helper_phys_cleanup(), the SSPPs attached to all LMs are
>> removed so clearing all the hardware. If the global state is still going to
>> retain the older configuration not reflecting this clear, it seems incorrect
>> to me. Thats why I was thinking of clearing all the SSPP mapping in
>> disable() or in the modeset prior to the disable as technically thats being
>> done in HW today anyway.
>>
>> During the next atomic check, the planes in the crtc's current state will
>> get re-attached and programmed to the blend stages. So this clearing of
>> global state is reflecting the current state of the corresponding hardware.
>
> The global state tracks resource allocation. If we clear the resources
> in the disable() path, we have no way to know which SSPP blocks were
> assigned to us in the corresponding enable() call path. There is no
> guarantee that there will be an atomic_check() between disable() and
> enable().
>
So I had suggested clearing in disable() because we did not come to an
agreement to doing it in atomic_check() just a few comments earlier.
Doing it in disable() is not right. I agree with that part now as we
should not be touching the state after atomic_check() phase.
That brings me back to my original question. With the planes_changed
check in atomic_check how can we guarantee that global state SSPP
allocation is freed and allocated again across a disable() / enable()
cycle? Can you pls confirm whether this is happening or not across a
hotplug and suspend/resume cycle?
>>
>>>>
>>>> Were you able to confirm whether the mapping gets cleared across
>>>> hotplugs or suspend/resumes? If so, it would confirm whether
>>>> planes_changed covers these aspects. Although, I think clearing should
>>>> be more explicit.
>>>
>>> I will check that tomorrow.
>>>
>>>> Another option could be for you to call dpu_rm_release_all_sspp() in
>>>> dpu_crtc_disable(). So that across a disable and enable we have a clear
>>>> mapping table. WDYT?
>>>
>>> Absolutely no. The RM state should only be changed when other object's
>>> state change - in atomic_check(). After that it is mostly r/o.
>>> enabling/disabling the resource shouldn't change resource assignment
>>> at all.
>>>
Ack but please check above.
>>>>
>>>>>>
>>>>>> Overall, mainly we want to make sure SSPPs are re-assigned when:
>>>>>>
>>>>>
>>>>> 0) plane size changes
>>>>>>> 1) format changes (RGB to YUV and vice-versa)
>>>>>> 2) Any modesets
>>>>>
>>>>> No
>>>>
>>>> I am not able to follow why this is different from any global state
>>>> mapping of other HW blocks that we do across modesets.
>>>
>>> DIfferent lifecycle requirements, I'd say.
>>>
>>>>
>>>>>
>>>>>> 3) Any disable/enable without modeset like connectors changed as SSPPs are
>>>>>> changing outputs there.
>>>>>
>>>>> Absolutely no, the logic should be the same as active vs enabled for
>>>>> CRTCs. Realloc resources only if the plane itself gets disabled or
>>>>> enabled. In all other cases the set of SSPP blocks should stay
>>>>> untouched.
>>>>>
>>>>
>>>> I am going to re-visit this later perhaps but if we incorporate my above
>>>> suggestion of clearing the mapping in disable() I will be partially
>>>> satisfied.
>>>
>>> No, resource mapping can not be cleaned in disable(). We do not do
>>> that for any other resource kind.
>>>
>>
>> That gets handled with the needs_modeset part today which is calling the
>> dpu_rm_release().
>
> In atomic_check() path, not in the disable() path.
>
>>
>>>>
>>>>>>
>>>>>> If we are covered for all these, let me know.
>>>>>>
>>>>>>> +
>>>>>>> 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 15679dd50c66..70757d876cc3 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;
>>>>>>> +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);
>>>>>>> @@ -814,8 +817,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 935ff6fd172c..479d4c172290 100644
>>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
>>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
>>>>>>> @@ -54,6 +54,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;
>>>>>>> @@ -128,6 +130,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];
>>>>>>> };
>>>>>>
>>>>>> This is the part which now looks odd and can be managed with rebase I guess.
>>>>>>
>>>>>> Are you planning to pull in the move resource allocation to crtc_id changes
>>>>>> first before this part? IOW, rebase this change on top of that?
>>>>>
>>>>> No. I do not. If you remember, several revisions ago the enc_id ->
>>>>> crtc_id was a part of the series, but we both agreed to drop it since it
>>>>> was not required for virtual planes. As such, I plan to land this one
>>>>> first (yes, having some of the resources tracked basing on enc_id and
>>>>> SSPP is tracked basing on crtc_id).
>>>>>
>>>>
>>>> Yes, I am not asking whether you will be absorbing those changes into
>>>> this series. Even I would not suggest doing that.
>>>>
>>>> I was asking whether you will merge the crtc_id based tracking first and
>>>> then apply this on top of that and not the other way around.
>>>>
>>>> Because with this specific line I am certain it will conflict as both
>>>> the series touch struct dpu_global_state.
>>>
>>> They touch different parts of it. So I'd prefer to land this one first
>>> and then land using crtc_id for mapping.
>>>
>>
>> I am okay to fixup any other issues which arise later on because we have the
>> modparam protection anyway but I think validating suspend/resume and hotplug
>> to ensure no black screens is required. If those two cases work fine on your
>> end, we can proceed.
>
> I have been validating these changes with hotplug events, yes. I wasn't
> checking the suspend/resume, but that's broken anyway, until we land
> https://patchwork.freedesktop.org/patch/606931/?series=135908&rev=2
>
Can you pls confirm once whether the global state mapping gets freed
across crtc disable/enable cycle with the planes_changed check? I think
it has to.
Other items are closed so snipping out below.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v6 7/9] drm/msm/dpu: add support for virtual planes
2024-11-01 20:37 ` Abhinav Kumar
@ 2024-11-01 20:53 ` Dmitry Baryshkov
2024-11-01 21:27 ` Abhinav Kumar
0 siblings, 1 reply; 30+ messages in thread
From: Dmitry Baryshkov @ 2024-11-01 20:53 UTC (permalink / raw)
To: Abhinav Kumar
Cc: Rob Clark, Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
linux-arm-msm, dri-devel, freedreno, linux-kernel
On Fri, Nov 01, 2024 at 01:37:03PM -0700, Abhinav Kumar wrote:
>
>
> On 10/31/2024 2:03 PM, Dmitry Baryshkov wrote:
> > On Thu, Oct 31, 2024 at 01:06:34PM -0700, Abhinav Kumar wrote:
> > >
> > >
> > > On 10/31/2024 8:11 AM, Dmitry Baryshkov wrote:
> > > > Hi Abhinav,
> > > >
> > > > On Wed, 30 Oct 2024 at 21:26, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
> > > > >
> > > > >
> > > > >
> > > > > On 10/30/2024 3:48 AM, Dmitry Baryshkov wrote:
> > > > > > On Tue, Oct 29, 2024 at 02:30:12PM -0700, Abhinav Kumar wrote:
> > > > > > >
> > > > > > >
> > > > > > > On 10/24/2024 5:20 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.
> > > > > > > >
> > > > > > > > As the planes are attached to the CRTC and not the encoder, the SSPP
> > > > > > > > blocks are also allocated per CRTC ID (all other resources are currently
> > > > > > > > allocated per encoder ID). This also matches the hardware requirement,
> > > > > > > > where both rectangles of a single SSPP can only be used with the LM
> > > > > > > > pair.
> > > > > > > >
> > > > > > > > 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 | 237 ++++++++++++++++++++++++++----
> > > > > > > > drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 16 ++
> > > > > > > > drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 68 +++++++++
> > > > > > > > drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 27 ++++
> > > > > > > > 7 files changed, 383 insertions(+), 29 deletions(-)
> > > > > > > >
> > > > > > > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > > > > > index 58595dcc3889..a7eea094aa14 100644
> > > > > > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > > > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > > > > > > @@ -1166,6 +1166,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)
> > > > > > > > {
> > > > > > > > @@ -1181,6 +1224,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;
> > > > > > > > + }
> > > > > > >
> > > > > > > planes_changed is set only for format changes . Will it cover all
> > > > > > > needs_modeset cases?
> > > > > > >
> > > > > > > OR do we also need to set planes_changed when
> > > > > > > drm_atomic_crtc_needs_modeset()?
> > > > > > >
> > > > > > > Unless I am missing something, I think we have to otherwise sspp
> > > > > > > reallocation wont happen in modeset cases.
> > > > > >
> > > > > > I was depending on the planes being included in the state by the client.
> > > > > > I don't think we really care about the modeset per se. We care about
> > > > > > plane size changes. And changing the size means that the plane is
> > > > > > included into the commit.
> > > > > >
> > > > >
> > > > > The global state mapping for SSPPs has to be cleared across modesets
> > > > > IMO. This is no different from us calling dpu_rm_release() today in
> > > > > dpu_encoder_virt_atomic_check(). I just am not sure whether
> > > > > planes_changed will cover all modeset conditions.
> > > >
> > > > We clear other resources, because they depend on the CRTC resolution.
> > > > Planes do not. Well, not until the quadpipe is in play.
> > > > SSPPs (currently) should be reallocated only if the _plane_'s
> > > > resolution change. If we have a modeset which involves CRTC resolution
> > > > change, but not the plane's size change, there is no need to
> > > > reallocate SSPPs.
> > > >
> > >
> > > In dpu_encoder_helper_phys_cleanup(), the SSPPs attached to all LMs are
> > > removed so clearing all the hardware. If the global state is still going to
> > > retain the older configuration not reflecting this clear, it seems incorrect
> > > to me. Thats why I was thinking of clearing all the SSPP mapping in
> > > disable() or in the modeset prior to the disable as technically thats being
> > > done in HW today anyway.
> > >
> > > During the next atomic check, the planes in the crtc's current state will
> > > get re-attached and programmed to the blend stages. So this clearing of
> > > global state is reflecting the current state of the corresponding hardware.
> >
> > The global state tracks resource allocation. If we clear the resources
> > in the disable() path, we have no way to know which SSPP blocks were
> > assigned to us in the corresponding enable() call path. There is no
> > guarantee that there will be an atomic_check() between disable() and
> > enable().
> >
>
> So I had suggested clearing in disable() because we did not come to an
> agreement to doing it in atomic_check() just a few comments earlier.
>
> Doing it in disable() is not right. I agree with that part now as we should
> not be touching the state after atomic_check() phase.
>
> That brings me back to my original question. With the planes_changed check
> in atomic_check how can we guarantee that global state SSPP allocation is
> freed and allocated again across a disable() / enable() cycle? Can you pls
> confirm whether this is happening or not across a hotplug and suspend/resume
> cycle?
disable() / enable() on which object? Because CRTC, if it
needs_modeset() || crtc_needs_disable() absolutely can go through a
disable / enable cycle, it doesn't require SSPP reallocation at all.
But maybe it's easier to just have drm_atomic_crtc_needs_modeset(). Will
that make it better for you?
>
>
> > >
> > > > >
> > > > > Were you able to confirm whether the mapping gets cleared across
> > > > > hotplugs or suspend/resumes? If so, it would confirm whether
> > > > > planes_changed covers these aspects. Although, I think clearing should
> > > > > be more explicit.
> > > >
> > > > I will check that tomorrow.
> > > >
> > > > > Another option could be for you to call dpu_rm_release_all_sspp() in
> > > > > dpu_crtc_disable(). So that across a disable and enable we have a clear
> > > > > mapping table. WDYT?
> > > >
> > > > Absolutely no. The RM state should only be changed when other object's
> > > > state change - in atomic_check(). After that it is mostly r/o.
> > > > enabling/disabling the resource shouldn't change resource assignment
> > > > at all.
> > > >
>
> Ack but please check above.
>
> > > > >
> > > > > > >
> > > > > > > Overall, mainly we want to make sure SSPPs are re-assigned when:
> > > > > > >
> > > > > >
> > > > > > 0) plane size changes
> > > > > > > > 1) format changes (RGB to YUV and vice-versa)
> > > > > > > 2) Any modesets
> > > > > >
> > > > > > No
> > > > >
> > > > > I am not able to follow why this is different from any global state
> > > > > mapping of other HW blocks that we do across modesets.
> > > >
> > > > DIfferent lifecycle requirements, I'd say.
> > > >
> > > > >
> > > > > >
> > > > > > > 3) Any disable/enable without modeset like connectors changed as SSPPs are
> > > > > > > changing outputs there.
> > > > > >
> > > > > > Absolutely no, the logic should be the same as active vs enabled for
> > > > > > CRTCs. Realloc resources only if the plane itself gets disabled or
> > > > > > enabled. In all other cases the set of SSPP blocks should stay
> > > > > > untouched.
> > > > > >
> > > > >
> > > > > I am going to re-visit this later perhaps but if we incorporate my above
> > > > > suggestion of clearing the mapping in disable() I will be partially
> > > > > satisfied.
> > > >
> > > > No, resource mapping can not be cleaned in disable(). We do not do
> > > > that for any other resource kind.
> > > >
> > >
> > > That gets handled with the needs_modeset part today which is calling the
> > > dpu_rm_release().
> >
> > In atomic_check() path, not in the disable() path.
> >
> > >
> > > > >
> > > > > > >
> > > > > > > If we are covered for all these, let me know.
> > > > > > >
> > > > > > > > +
> > > > > > > > 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 15679dd50c66..70757d876cc3 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;
> > > > > > > > +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);
> > > > > > > > @@ -814,8 +817,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 935ff6fd172c..479d4c172290 100644
> > > > > > > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
> > > > > > > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
> > > > > > > > @@ -54,6 +54,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;
> > > > > > > > @@ -128,6 +130,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];
> > > > > > > > };
> > > > > > >
> > > > > > > This is the part which now looks odd and can be managed with rebase I guess.
> > > > > > >
> > > > > > > Are you planning to pull in the move resource allocation to crtc_id changes
> > > > > > > first before this part? IOW, rebase this change on top of that?
> > > > > >
> > > > > > No. I do not. If you remember, several revisions ago the enc_id ->
> > > > > > crtc_id was a part of the series, but we both agreed to drop it since it
> > > > > > was not required for virtual planes. As such, I plan to land this one
> > > > > > first (yes, having some of the resources tracked basing on enc_id and
> > > > > > SSPP is tracked basing on crtc_id).
> > > > > >
> > > > >
> > > > > Yes, I am not asking whether you will be absorbing those changes into
> > > > > this series. Even I would not suggest doing that.
> > > > >
> > > > > I was asking whether you will merge the crtc_id based tracking first and
> > > > > then apply this on top of that and not the other way around.
> > > > >
> > > > > Because with this specific line I am certain it will conflict as both
> > > > > the series touch struct dpu_global_state.
> > > >
> > > > They touch different parts of it. So I'd prefer to land this one first
> > > > and then land using crtc_id for mapping.
> > > >
> > >
> > > I am okay to fixup any other issues which arise later on because we have the
> > > modparam protection anyway but I think validating suspend/resume and hotplug
> > > to ensure no black screens is required. If those two cases work fine on your
> > > end, we can proceed.
> >
> > I have been validating these changes with hotplug events, yes. I wasn't
> > checking the suspend/resume, but that's broken anyway, until we land
> > https://patchwork.freedesktop.org/patch/606931/?series=135908&rev=2
> >
>
> Can you pls confirm once whether the global state mapping gets freed across
> crtc disable/enable cycle with the planes_changed check? I think it has to.
I think you are asking the question from the wrong side. What kind of
commit leads to that CRTC disable/enable cycle?
>
> Other items are closed so snipping out below.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v6 7/9] drm/msm/dpu: add support for virtual planes
2024-11-01 20:53 ` Dmitry Baryshkov
@ 2024-11-01 21:27 ` Abhinav Kumar
2024-11-01 23:30 ` Abhinav Kumar
0 siblings, 1 reply; 30+ messages in thread
From: Abhinav Kumar @ 2024-11-01 21:27 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Rob Clark, Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
linux-arm-msm, dri-devel, freedreno, linux-kernel
On 11/1/2024 1:53 PM, Dmitry Baryshkov wrote:
> On Fri, Nov 01, 2024 at 01:37:03PM -0700, Abhinav Kumar wrote:
>>
>>
>> On 10/31/2024 2:03 PM, Dmitry Baryshkov wrote:
>>> On Thu, Oct 31, 2024 at 01:06:34PM -0700, Abhinav Kumar wrote:
>>>>
>>>>
>>>> On 10/31/2024 8:11 AM, Dmitry Baryshkov wrote:
>>>>> Hi Abhinav,
>>>>>
>>>>> On Wed, 30 Oct 2024 at 21:26, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>> On 10/30/2024 3:48 AM, Dmitry Baryshkov wrote:
>>>>>>> On Tue, Oct 29, 2024 at 02:30:12PM -0700, Abhinav Kumar wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>> On 10/24/2024 5:20 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.
>>>>>>>>>
>>>>>>>>> As the planes are attached to the CRTC and not the encoder, the SSPP
>>>>>>>>> blocks are also allocated per CRTC ID (all other resources are currently
>>>>>>>>> allocated per encoder ID). This also matches the hardware requirement,
>>>>>>>>> where both rectangles of a single SSPP can only be used with the LM
>>>>>>>>> pair.
>>>>>>>>>
>>>>>>>>> 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 | 237 ++++++++++++++++++++++++++----
>>>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 16 ++
>>>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 68 +++++++++
>>>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 27 ++++
>>>>>>>>> 7 files changed, 383 insertions(+), 29 deletions(-)
>>>>>>>>>
>>>>>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>>>>>> index 58595dcc3889..a7eea094aa14 100644
>>>>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>>>>>> @@ -1166,6 +1166,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)
>>>>>>>>> {
>>>>>>>>> @@ -1181,6 +1224,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;
>>>>>>>>> + }
>>>>>>>>
>>>>>>>> planes_changed is set only for format changes . Will it cover all
>>>>>>>> needs_modeset cases?
>>>>>>>>
>>>>>>>> OR do we also need to set planes_changed when
>>>>>>>> drm_atomic_crtc_needs_modeset()?
>>>>>>>>
>>>>>>>> Unless I am missing something, I think we have to otherwise sspp
>>>>>>>> reallocation wont happen in modeset cases.
>>>>>>>
>>>>>>> I was depending on the planes being included in the state by the client.
>>>>>>> I don't think we really care about the modeset per se. We care about
>>>>>>> plane size changes. And changing the size means that the plane is
>>>>>>> included into the commit.
>>>>>>>
>>>>>>
>>>>>> The global state mapping for SSPPs has to be cleared across modesets
>>>>>> IMO. This is no different from us calling dpu_rm_release() today in
>>>>>> dpu_encoder_virt_atomic_check(). I just am not sure whether
>>>>>> planes_changed will cover all modeset conditions.
>>>>>
>>>>> We clear other resources, because they depend on the CRTC resolution.
>>>>> Planes do not. Well, not until the quadpipe is in play.
>>>>> SSPPs (currently) should be reallocated only if the _plane_'s
>>>>> resolution change. If we have a modeset which involves CRTC resolution
>>>>> change, but not the plane's size change, there is no need to
>>>>> reallocate SSPPs.
>>>>>
>>>>
>>>> In dpu_encoder_helper_phys_cleanup(), the SSPPs attached to all LMs are
>>>> removed so clearing all the hardware. If the global state is still going to
>>>> retain the older configuration not reflecting this clear, it seems incorrect
>>>> to me. Thats why I was thinking of clearing all the SSPP mapping in
>>>> disable() or in the modeset prior to the disable as technically thats being
>>>> done in HW today anyway.
>>>>
>>>> During the next atomic check, the planes in the crtc's current state will
>>>> get re-attached and programmed to the blend stages. So this clearing of
>>>> global state is reflecting the current state of the corresponding hardware.
>>>
>>> The global state tracks resource allocation. If we clear the resources
>>> in the disable() path, we have no way to know which SSPP blocks were
>>> assigned to us in the corresponding enable() call path. There is no
>>> guarantee that there will be an atomic_check() between disable() and
>>> enable().
>>>
>>
>> So I had suggested clearing in disable() because we did not come to an
>> agreement to doing it in atomic_check() just a few comments earlier.
>>
>> Doing it in disable() is not right. I agree with that part now as we should
>> not be touching the state after atomic_check() phase.
>>
>> That brings me back to my original question. With the planes_changed check
>> in atomic_check how can we guarantee that global state SSPP allocation is
>> freed and allocated again across a disable() / enable() cycle? Can you pls
>> confirm whether this is happening or not across a hotplug and suspend/resume
>> cycle?
>
> disable() / enable() on which object? Because CRTC, if it
> needs_modeset() || crtc_needs_disable() absolutely can go through a
> disable / enable cycle, it doesn't require SSPP reallocation at all.
>
This is the part I am failing to understand. So as I wrote above, across
a disable() / enable() cycle the SSPPs are cleared from the LMs and
re-attached on the commit which enables() the CRTC back.
All that I am saying is that the global state SSPP mapping to the
crtc_id should also reflect this clearing. Otherwise this will lead to a
mismatch of states.
> But maybe it's easier to just have drm_atomic_crtc_needs_modeset(). Will
> that make it better for you?
>
Yes this is exactly what I had requested in my first response on this
thread.
>>
>>
>>>>
>>>>>>
>>>>>> Were you able to confirm whether the mapping gets cleared across
>>>>>> hotplugs or suspend/resumes? If so, it would confirm whether
>>>>>> planes_changed covers these aspects. Although, I think clearing should
>>>>>> be more explicit.
>>>>>
>>>>> I will check that tomorrow.
>>>>>
>>>>>> Another option could be for you to call dpu_rm_release_all_sspp() in
>>>>>> dpu_crtc_disable(). So that across a disable and enable we have a clear
>>>>>> mapping table. WDYT?
>>>>>
>>>>> Absolutely no. The RM state should only be changed when other object's
>>>>> state change - in atomic_check(). After that it is mostly r/o.
>>>>> enabling/disabling the resource shouldn't change resource assignment
>>>>> at all.
>>>>>
>>
>> Ack but please check above.
>>
>>>>>>
>>>>>>>>
>>>>>>>> Overall, mainly we want to make sure SSPPs are re-assigned when:
>>>>>>>>
>>>>>>>
>>>>>>> 0) plane size changes
>>>>>>>>> 1) format changes (RGB to YUV and vice-versa)
>>>>>>>> 2) Any modesets
>>>>>>>
>>>>>>> No
>>>>>>
>>>>>> I am not able to follow why this is different from any global state
>>>>>> mapping of other HW blocks that we do across modesets.
>>>>>
>>>>> DIfferent lifecycle requirements, I'd say.
>>>>>
>>>>>>
>>>>>>>
>>>>>>>> 3) Any disable/enable without modeset like connectors changed as SSPPs are
>>>>>>>> changing outputs there.
>>>>>>>
>>>>>>> Absolutely no, the logic should be the same as active vs enabled for
>>>>>>> CRTCs. Realloc resources only if the plane itself gets disabled or
>>>>>>> enabled. In all other cases the set of SSPP blocks should stay
>>>>>>> untouched.
>>>>>>>
>>>>>>
>>>>>> I am going to re-visit this later perhaps but if we incorporate my above
>>>>>> suggestion of clearing the mapping in disable() I will be partially
>>>>>> satisfied.
>>>>>
>>>>> No, resource mapping can not be cleaned in disable(). We do not do
>>>>> that for any other resource kind.
>>>>>
>>>>
>>>> That gets handled with the needs_modeset part today which is calling the
>>>> dpu_rm_release().
>>>
>>> In atomic_check() path, not in the disable() path.
>>>
>>>>
>>>>>>
>>>>>>>>
>>>>>>>> If we are covered for all these, let me know.
>>>>>>>>
>>>>>>>>> +
>>>>>>>>> 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 15679dd50c66..70757d876cc3 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;
>>>>>>>>> +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);
>>>>>>>>> @@ -814,8 +817,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 935ff6fd172c..479d4c172290 100644
>>>>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
>>>>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
>>>>>>>>> @@ -54,6 +54,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;
>>>>>>>>> @@ -128,6 +130,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];
>>>>>>>>> };
>>>>>>>>
>>>>>>>> This is the part which now looks odd and can be managed with rebase I guess.
>>>>>>>>
>>>>>>>> Are you planning to pull in the move resource allocation to crtc_id changes
>>>>>>>> first before this part? IOW, rebase this change on top of that?
>>>>>>>
>>>>>>> No. I do not. If you remember, several revisions ago the enc_id ->
>>>>>>> crtc_id was a part of the series, but we both agreed to drop it since it
>>>>>>> was not required for virtual planes. As such, I plan to land this one
>>>>>>> first (yes, having some of the resources tracked basing on enc_id and
>>>>>>> SSPP is tracked basing on crtc_id).
>>>>>>>
>>>>>>
>>>>>> Yes, I am not asking whether you will be absorbing those changes into
>>>>>> this series. Even I would not suggest doing that.
>>>>>>
>>>>>> I was asking whether you will merge the crtc_id based tracking first and
>>>>>> then apply this on top of that and not the other way around.
>>>>>>
>>>>>> Because with this specific line I am certain it will conflict as both
>>>>>> the series touch struct dpu_global_state.
>>>>>
>>>>> They touch different parts of it. So I'd prefer to land this one first
>>>>> and then land using crtc_id for mapping.
>>>>>
>>>>
>>>> I am okay to fixup any other issues which arise later on because we have the
>>>> modparam protection anyway but I think validating suspend/resume and hotplug
>>>> to ensure no black screens is required. If those two cases work fine on your
>>>> end, we can proceed.
>>>
>>> I have been validating these changes with hotplug events, yes. I wasn't
>>> checking the suspend/resume, but that's broken anyway, until we land
>>> https://patchwork.freedesktop.org/patch/606931/?series=135908&rev=2
>>>
>>
>> Can you pls confirm once whether the global state mapping gets freed across
>> crtc disable/enable cycle with the planes_changed check? I think it has to.
>
> I think you are asking the question from the wrong side. What kind of
> commit leads to that CRTC disable/enable cycle?
>
A commit which requires modeset?
>>
>> Other items are closed so snipping out below.
>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v6 7/9] drm/msm/dpu: add support for virtual planes
2024-11-01 21:27 ` Abhinav Kumar
@ 2024-11-01 23:30 ` Abhinav Kumar
0 siblings, 0 replies; 30+ messages in thread
From: Abhinav Kumar @ 2024-11-01 23:30 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Rob Clark, Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
linux-arm-msm, dri-devel, freedreno, linux-kernel
On 11/1/2024 2:27 PM, Abhinav Kumar wrote:
>
>
> On 11/1/2024 1:53 PM, Dmitry Baryshkov wrote:
>> On Fri, Nov 01, 2024 at 01:37:03PM -0700, Abhinav Kumar wrote:
>>>
>>>
>>> On 10/31/2024 2:03 PM, Dmitry Baryshkov wrote:
>>>> On Thu, Oct 31, 2024 at 01:06:34PM -0700, Abhinav Kumar wrote:
>>>>>
>>>>>
>>>>> On 10/31/2024 8:11 AM, Dmitry Baryshkov wrote:
>>>>>> Hi Abhinav,
>>>>>>
>>>>>> On Wed, 30 Oct 2024 at 21:26, Abhinav Kumar
>>>>>> <quic_abhinavk@quicinc.com> wrote:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On 10/30/2024 3:48 AM, Dmitry Baryshkov wrote:
>>>>>>>> On Tue, Oct 29, 2024 at 02:30:12PM -0700, Abhinav Kumar wrote:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On 10/24/2024 5:20 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.
>>>>>>>>>>
>>>>>>>>>> As the planes are attached to the CRTC and not the encoder,
>>>>>>>>>> the SSPP
>>>>>>>>>> blocks are also allocated per CRTC ID (all other resources are
>>>>>>>>>> currently
>>>>>>>>>> allocated per encoder ID). This also matches the hardware
>>>>>>>>>> requirement,
>>>>>>>>>> where both rectangles of a single SSPP can only be used with
>>>>>>>>>> the LM
>>>>>>>>>> pair.
>>>>>>>>>>
>>>>>>>>>> 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 | 237
>>>>>>>>>> ++++++++++++++++++++++++++----
>>>>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 16 ++
>>>>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 68 +++++++++
>>>>>>>>>> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 27 ++++
>>>>>>>>>> 7 files changed, 383 insertions(+), 29 deletions(-)
>>>>>>>>>>
>>>>>>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>>>>>>> b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>>>>>>> index 58595dcc3889..a7eea094aa14 100644
>>>>>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
>>>>>>>>>> @@ -1166,6 +1166,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)
>>>>>>>>>> {
>>>>>>>>>> @@ -1181,6 +1224,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;
>>>>>>>>>> + }
>>>>>>>>>
>>>>>>>>> planes_changed is set only for format changes . Will it cover all
>>>>>>>>> needs_modeset cases?
>>>>>>>>>
>>>>>>>>> OR do we also need to set planes_changed when
>>>>>>>>> drm_atomic_crtc_needs_modeset()?
>>>>>>>>>
>>>>>>>>> Unless I am missing something, I think we have to otherwise sspp
>>>>>>>>> reallocation wont happen in modeset cases.
>>>>>>>>
>>>>>>>> I was depending on the planes being included in the state by the
>>>>>>>> client.
>>>>>>>> I don't think we really care about the modeset per se. We care
>>>>>>>> about
>>>>>>>> plane size changes. And changing the size means that the plane is
>>>>>>>> included into the commit.
>>>>>>>>
>>>>>>>
>>>>>>> The global state mapping for SSPPs has to be cleared across modesets
>>>>>>> IMO. This is no different from us calling dpu_rm_release() today in
>>>>>>> dpu_encoder_virt_atomic_check(). I just am not sure whether
>>>>>>> planes_changed will cover all modeset conditions.
>>>>>>
>>>>>> We clear other resources, because they depend on the CRTC resolution.
>>>>>> Planes do not. Well, not until the quadpipe is in play.
>>>>>> SSPPs (currently) should be reallocated only if the _plane_'s
>>>>>> resolution change. If we have a modeset which involves CRTC
>>>>>> resolution
>>>>>> change, but not the plane's size change, there is no need to
>>>>>> reallocate SSPPs.
>>>>>>
>>>>>
>>>>> In dpu_encoder_helper_phys_cleanup(), the SSPPs attached to all LMs
>>>>> are
>>>>> removed so clearing all the hardware. If the global state is still
>>>>> going to
>>>>> retain the older configuration not reflecting this clear, it seems
>>>>> incorrect
>>>>> to me. Thats why I was thinking of clearing all the SSPP mapping in
>>>>> disable() or in the modeset prior to the disable as technically
>>>>> thats being
>>>>> done in HW today anyway.
>>>>>
>>>>> During the next atomic check, the planes in the crtc's current
>>>>> state will
>>>>> get re-attached and programmed to the blend stages. So this
>>>>> clearing of
>>>>> global state is reflecting the current state of the corresponding
>>>>> hardware.
>>>>
>>>> The global state tracks resource allocation. If we clear the resources
>>>> in the disable() path, we have no way to know which SSPP blocks were
>>>> assigned to us in the corresponding enable() call path. There is no
>>>> guarantee that there will be an atomic_check() between disable() and
>>>> enable().
>>>>
>>>
>>> So I had suggested clearing in disable() because we did not come to an
>>> agreement to doing it in atomic_check() just a few comments earlier.
>>>
>>> Doing it in disable() is not right. I agree with that part now as we
>>> should
>>> not be touching the state after atomic_check() phase.
>>>
>>> That brings me back to my original question. With the planes_changed
>>> check
>>> in atomic_check how can we guarantee that global state SSPP
>>> allocation is
>>> freed and allocated again across a disable() / enable() cycle? Can
>>> you pls
>>> confirm whether this is happening or not across a hotplug and
>>> suspend/resume
>>> cycle?
>>
>> disable() / enable() on which object? Because CRTC, if it
>> needs_modeset() || crtc_needs_disable() absolutely can go through a
>> disable / enable cycle, it doesn't require SSPP reallocation at all.
>>
>
> This is the part I am failing to understand. So as I wrote above, across
> a disable() / enable() cycle the SSPPs are cleared from the LMs and
> re-attached on the commit which enables() the CRTC back.
>
> All that I am saying is that the global state SSPP mapping to the
> crtc_id should also reflect this clearing. Otherwise this will lead to a
> mismatch of states.
>
>
>> But maybe it's easier to just have drm_atomic_crtc_needs_modeset(). Will
>> that make it better for you?
>>
>
> Yes this is exactly what I had requested in my first response on this
> thread.
>
Summarizing our discussion from IRC:
I was more interested in the case where there is only one SSPP and lets
say it was bound to CRTC0. Then CRTC0 gets disabled and CRTC1 gets
enabled. Then we will have to free up the SSPP from CRTC0.
But based on our discussion, drm_atomic_helper_disable_plane() should
get called which in-turn will lead to planes_chaged to be set.
With this in mind, from the code review standpoint, I cannot think of
basic test-cases which can get broken, hence,
Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
From validation standpoint, I would certainly like to test more myself
but nothing immediately which i can hold back this change for.
>>>
>>>
>>>>>
>>>>>>>
>>>>>>> Were you able to confirm whether the mapping gets cleared across
>>>>>>> hotplugs or suspend/resumes? If so, it would confirm whether
>>>>>>> planes_changed covers these aspects. Although, I think clearing
>>>>>>> should
>>>>>>> be more explicit.
>>>>>>
>>>>>> I will check that tomorrow.
>>>>>>
>>>>>>> Another option could be for you to call dpu_rm_release_all_sspp() in
>>>>>>> dpu_crtc_disable(). So that across a disable and enable we have a
>>>>>>> clear
>>>>>>> mapping table. WDYT?
>>>>>>
>>>>>> Absolutely no. The RM state should only be changed when other
>>>>>> object's
>>>>>> state change - in atomic_check(). After that it is mostly r/o.
>>>>>> enabling/disabling the resource shouldn't change resource assignment
>>>>>> at all.
>>>>>>
>>>
>>> Ack but please check above.
>>>
>>>>>>>
>>>>>>>>>
>>>>>>>>> Overall, mainly we want to make sure SSPPs are re-assigned when:
>>>>>>>>>
>>>>>>>>
>>>>>>>> 0) plane size changes
>>>>>>>>>> 1) format changes (RGB to YUV and vice-versa)
>>>>>>>>> 2) Any modesets
>>>>>>>>
>>>>>>>> No
>>>>>>>
>>>>>>> I am not able to follow why this is different from any global state
>>>>>>> mapping of other HW blocks that we do across modesets.
>>>>>>
>>>>>> DIfferent lifecycle requirements, I'd say.
>>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>>> 3) Any disable/enable without modeset like connectors changed
>>>>>>>>> as SSPPs are
>>>>>>>>> changing outputs there.
>>>>>>>>
>>>>>>>> Absolutely no, the logic should be the same as active vs enabled
>>>>>>>> for
>>>>>>>> CRTCs. Realloc resources only if the plane itself gets disabled or
>>>>>>>> enabled. In all other cases the set of SSPP blocks should stay
>>>>>>>> untouched.
>>>>>>>>
>>>>>>>
>>>>>>> I am going to re-visit this later perhaps but if we incorporate
>>>>>>> my above
>>>>>>> suggestion of clearing the mapping in disable() I will be partially
>>>>>>> satisfied.
>>>>>>
>>>>>> No, resource mapping can not be cleaned in disable(). We do not do
>>>>>> that for any other resource kind.
>>>>>>
>>>>>
>>>>> That gets handled with the needs_modeset part today which is
>>>>> calling the
>>>>> dpu_rm_release().
>>>>
>>>> In atomic_check() path, not in the disable() path.
>>>>
>>>>>
>>>>>>>
>>>>>>>>>
>>>>>>>>> If we are covered for all these, let me know.
>>>>>>>>>
>>>>>>>>>> +
>>>>>>>>>> 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 15679dd50c66..70757d876cc3 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;
>>>>>>>>>> +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);
>>>>>>>>>> @@ -814,8 +817,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 935ff6fd172c..479d4c172290 100644
>>>>>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
>>>>>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
>>>>>>>>>> @@ -54,6 +54,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;
>>>>>>>>>> @@ -128,6 +130,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];
>>>>>>>>>> };
>>>>>>>>>
>>>>>>>>> This is the part which now looks odd and can be managed with
>>>>>>>>> rebase I guess.
>>>>>>>>>
>>>>>>>>> Are you planning to pull in the move resource allocation to
>>>>>>>>> crtc_id changes
>>>>>>>>> first before this part? IOW, rebase this change on top of that?
>>>>>>>>
>>>>>>>> No. I do not. If you remember, several revisions ago the enc_id ->
>>>>>>>> crtc_id was a part of the series, but we both agreed to drop it
>>>>>>>> since it
>>>>>>>> was not required for virtual planes. As such, I plan to land
>>>>>>>> this one
>>>>>>>> first (yes, having some of the resources tracked basing on
>>>>>>>> enc_id and
>>>>>>>> SSPP is tracked basing on crtc_id).
>>>>>>>>
>>>>>>>
>>>>>>> Yes, I am not asking whether you will be absorbing those changes
>>>>>>> into
>>>>>>> this series. Even I would not suggest doing that.
>>>>>>>
>>>>>>> I was asking whether you will merge the crtc_id based tracking
>>>>>>> first and
>>>>>>> then apply this on top of that and not the other way around.
>>>>>>>
>>>>>>> Because with this specific line I am certain it will conflict as
>>>>>>> both
>>>>>>> the series touch struct dpu_global_state.
>>>>>>
>>>>>> They touch different parts of it. So I'd prefer to land this one
>>>>>> first
>>>>>> and then land using crtc_id for mapping.
>>>>>>
>>>>>
>>>>> I am okay to fixup any other issues which arise later on because we
>>>>> have the
>>>>> modparam protection anyway but I think validating suspend/resume
>>>>> and hotplug
>>>>> to ensure no black screens is required. If those two cases work
>>>>> fine on your
>>>>> end, we can proceed.
>>>>
>>>> I have been validating these changes with hotplug events, yes. I wasn't
>>>> checking the suspend/resume, but that's broken anyway, until we land
>>>> https://patchwork.freedesktop.org/patch/606931/?series=135908&rev=2
>>>>
>>>
>>> Can you pls confirm once whether the global state mapping gets freed
>>> across
>>> crtc disable/enable cycle with the planes_changed check? I think it
>>> has to.
>>
>> I think you are asking the question from the wrong side. What kind of
>> commit leads to that CRTC disable/enable cycle?
>>
>
> A commit which requires modeset?
>
>>>
>>> Other items are closed so snipping out below.
>>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v6 0/9] drm/msm/dpu: support virtual wide planes
2024-10-25 0:20 [PATCH v6 0/9] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
` (8 preceding siblings ...)
2024-10-25 0:20 ` [PATCH v6 9/9] drm/msm/dpu: include SSPP allocation state into the dumped state Dmitry Baryshkov
@ 2024-11-02 1:08 ` Dmitry Baryshkov
9 siblings, 0 replies; 30+ messages in thread
From: Dmitry Baryshkov @ 2024-11-02 1:08 UTC (permalink / raw)
To: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten, David Airlie,
Simona Vetter, Dmitry Baryshkov
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
On Fri, 25 Oct 2024 03:20:07 +0300, Dmitry Baryshkov 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.
>
> [...]
Applied, thanks!
After additional consideration, apply only basic patches, leaving the virtual
planes enablement into the 6.14 material in order to be able to get more
testing for those patches.
[1/9] drm/msm/dpu: use drm_rect_fp_to_int()
https://gitlab.freedesktop.org/lumag/msm/-/commit/50024444c44c
[2/9] drm/msm/dpu: move pstate->pipe initialization to dpu_plane_atomic_check
https://gitlab.freedesktop.org/lumag/msm/-/commit/31f7148fd370
[3/9] drm/msm/dpu: drop virt_formats from SSPP subblock configuration
https://gitlab.freedesktop.org/lumag/msm/-/commit/b96ca23fdd03
[4/9] drm/msm/dpu: move scaling limitations out of the hw_catalog
https://gitlab.freedesktop.org/lumag/msm/-/commit/8f15005783b8
[5/9] drm/msm/dpu: split dpu_plane_atomic_check()
https://gitlab.freedesktop.org/lumag/msm/-/commit/dbbf57dfd04e
[6/9] drm/msm/dpu: move rot90 checking to dpu_plane_atomic_check_sspp()
https://gitlab.freedesktop.org/lumag/msm/-/commit/ab52d2717ac0
Best regards,
--
Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2024-11-02 1:08 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-25 0:20 [PATCH v6 0/9] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
2024-10-25 0:20 ` [PATCH v6 1/9] drm/msm/dpu: use drm_rect_fp_to_int() Dmitry Baryshkov
2024-10-25 0:20 ` [PATCH v6 2/9] drm/msm/dpu: move pstate->pipe initialization to dpu_plane_atomic_check Dmitry Baryshkov
2024-10-25 19:00 ` Abhinav Kumar
2024-10-28 10:46 ` Dmitry Baryshkov
2024-10-29 20:42 ` Abhinav Kumar
2024-10-25 0:20 ` [PATCH v6 3/9] drm/msm/dpu: drop virt_formats from SSPP subblock configuration Dmitry Baryshkov
2024-10-25 0:20 ` [PATCH v6 4/9] drm/msm/dpu: move scaling limitations out of the hw_catalog Dmitry Baryshkov
2024-10-25 23:15 ` Abhinav Kumar
2024-10-25 0:20 ` [PATCH v6 5/9] drm/msm/dpu: split dpu_plane_atomic_check() Dmitry Baryshkov
2024-10-25 23:21 ` Abhinav Kumar
2024-10-25 0:20 ` [PATCH v6 6/9] drm/msm/dpu: move rot90 checking to dpu_plane_atomic_check_sspp() Dmitry Baryshkov
2024-10-29 21:00 ` Abhinav Kumar
2024-10-25 0:20 ` [PATCH v6 7/9] drm/msm/dpu: add support for virtual planes Dmitry Baryshkov
2024-10-29 21:30 ` Abhinav Kumar
2024-10-30 10:48 ` Dmitry Baryshkov
2024-10-30 19:26 ` Abhinav Kumar
2024-10-31 15:11 ` Dmitry Baryshkov
2024-10-31 15:17 ` Dmitry Baryshkov
2024-10-31 20:06 ` Abhinav Kumar
2024-10-31 21:03 ` Dmitry Baryshkov
2024-11-01 20:37 ` Abhinav Kumar
2024-11-01 20:53 ` Dmitry Baryshkov
2024-11-01 21:27 ` Abhinav Kumar
2024-11-01 23:30 ` Abhinav Kumar
2024-10-25 0:20 ` [PATCH v6 8/9] drm/msm/dpu: allow using two SSPP blocks for a single plane Dmitry Baryshkov
2024-10-29 22:07 ` Abhinav Kumar
2024-10-30 10:03 ` Dmitry Baryshkov
2024-10-25 0:20 ` [PATCH v6 9/9] drm/msm/dpu: include SSPP allocation state into the dumped state Dmitry Baryshkov
2024-11-02 1:08 ` [PATCH v6 0/9] drm/msm/dpu: support virtual wide planes Dmitry Baryshkov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox