@@ -738,13 +738,22 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms)
for (i = 0; i < catalog->sspp_count; i++) {
enum drm_plane_type type;
- if ((catalog->sspp[i].features & BIT(DPU_SSPP_CURSOR))
- && cursor_planes_idx < max_crtc_count)
- type = DRM_PLANE_TYPE_CURSOR;
- else if (primary_planes_idx < max_crtc_count)
+ if (catalog->sspp[i].features & BIT(DPU_SSPP_CURSOR)) {
+ if (cursor_planes_idx < max_crtc_count) {
+ type = DRM_PLANE_TYPE_CURSOR;
+ } else if (catalog->sspp[i].type == SSPP_TYPE_CURSOR) {
+ /* Cursor SSPP can only be used in the last
+ * mixer stage, so it doesn't make sense to
+ * assign two of those to the same CRTC */
+ continue;
+ } else {
+ type = DRM_PLANE_TYPE_OVERLAY;
+ }
+ } else if (primary_planes_idx < max_crtc_count) {
type = DRM_PLANE_TYPE_PRIMARY;
- else
+ } else {
type = DRM_PLANE_TYPE_OVERLAY;
+ }
DPU_DEBUG("Create plane type %d with features %lx (cur %lx)\n",
type, catalog->sspp[i].features,
@@ -881,7 +881,14 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
r_pipe->sspp = NULL;
- pstate->stage = DPU_STAGE_BASE + pstate->base.normalized_zpos;
+ if (pipe_hw_caps->type == SSPP_TYPE_CURSOR) {
+ /* enforce cursor sspp to use the last mixer stage */
+ pstate->stage = DPU_STAGE_BASE +
+ pdpu->catalog->caps->max_mixer_blendstages;
+ } else {
+ pstate->stage = DPU_STAGE_BASE + pstate->base.normalized_zpos;
+ }
+
if (pstate->stage > DPU_STAGE_BASE + pdpu->catalog->caps->max_mixer_blendstages) {
DPU_ERROR("> %d plane mixer stages assigned\n",
pdpu->catalog->caps->max_mixer_blendstages);
@@ -1463,6 +1470,7 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
struct msm_drm_private *priv = dev->dev_private;
struct dpu_kms *kms = to_dpu_kms(priv->kms);
struct dpu_hw_sspp *pipe_hw;
+ const uint64_t *format_modifiers;
uint32_t num_formats;
uint32_t supported_rotations;
int ret = -EINVAL;
@@ -1489,15 +1497,27 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
format_list = pipe_hw->cap->sblk->format_list;
num_formats = pipe_hw->cap->sblk->num_formats;
+ if (pipe_hw->cap->type == SSPP_TYPE_CURSOR)
+ format_modifiers = NULL;
+ else
+ format_modifiers = supported_format_modifiers;
+
ret = drm_universal_plane_init(dev, plane, 0xff, &dpu_plane_funcs,
format_list, num_formats,
- supported_format_modifiers, type, NULL);
+ format_modifiers, type, NULL);
if (ret)
goto clean_plane;
pdpu->catalog = kms->catalog;
- ret = drm_plane_create_zpos_property(plane, 0, 0, DPU_ZPOS_MAX);
+ if (pipe_hw->cap->type == SSPP_TYPE_CURSOR) {
+ /* cursor SSPP can only be used in the last mixer stage,
+ * enforce it by maxing out the cursor plane zpos */
+ ret = drm_plane_create_zpos_immutable_property(plane, DPU_ZPOS_MAX);
+ } else {
+ ret = drm_plane_create_zpos_property(plane, 0, 0, DPU_ZPOS_MAX - 1);
+ }
+
if (ret)
DPU_ERROR("failed to install zpos property, rc = %d\n", ret);
Cursor SSPP must be assigned to the last mixer stage, so we assign an immutable zpos property with a value higher than primary/overlay planes, to ensure it will always be on top. Signed-off-by: Arnaud Vrac <avrac@freebox.fr> --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 19 ++++++++++++++----- drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 26 +++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 8 deletions(-)