From 672b3c4bc3d157078c00146c2d20bdd3aeec38e6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 29 May 2018 21:28:00 +0300 Subject: [PATCH] drm/i915: Fix sprite destination colorkeying on SKL+ MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit On SKL+ the dst colorkey must be configured on the lower plane that contains the colorkey. This is in contrast to most earlier platforms where the dst colorkey is configured on the plane above. The hardware will peform dst keying only between two immediately adjacent (in zorder) planes. Plane 2 will be keyed against plane 1, plane 3 againts plane 2, and so on. There is no way to key arbitrary planes against plane 1. Thus offering dst color keying on plane 3+ is pointless. In fact it can be harmful since enabling dst keying on more than one plane on the same pipe leads to only the top-most of the planes performing the keying. For any plane lower in zorder the dst key enable is simply ignored. v2: s/plane 0/plane 1/ etc. since the hw plane names start from 1 Don't break dst colorkey on pre-SKL sprites (hunk ended in the wrong patch) Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180529182804.8571-1-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy #v1 --- drivers/gpu/drm/i915/intel_sprite.c | 64 +++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 24f86c4375cf..d9e7f4fb5096 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1175,6 +1175,37 @@ intel_check_sprite_plane(struct intel_plane *plane, return 0; } +static bool has_dst_key_in_primary_plane(struct drm_i915_private *dev_priv) +{ + return INTEL_GEN(dev_priv) >= 9; +} + +static void intel_plane_set_ckey(struct intel_plane_state *plane_state, + const struct drm_intel_sprite_colorkey *set) +{ + struct intel_plane *plane = to_intel_plane(plane_state->base.plane); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + struct drm_intel_sprite_colorkey *key = &plane_state->ckey; + + *key = *set; + + /* + * We want src key enabled on the + * sprite and not on the primary. + */ + if (plane->id == PLANE_PRIMARY && + set->flags & I915_SET_COLORKEY_SOURCE) + key->flags = 0; + + /* + * On SKL+ we want dst key enabled on + * the primary and not on the sprite. + */ + if (INTEL_GEN(dev_priv) >= 9 && plane->id != PLANE_PRIMARY && + set->flags & I915_SET_COLORKEY_DESTINATION) + key->flags = 0; +} + int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -1204,6 +1235,16 @@ int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data, if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) return -ENOENT; + /* + * SKL+ only plane 2 can do destination keying against plane 1. + * Also multiple planes can't do destination keying on the same + * pipe simultaneously. + */ + if (INTEL_GEN(dev_priv) >= 9 && + to_intel_plane(plane)->id >= PLANE_SPRITE1 && + set->flags & I915_SET_COLORKEY_DESTINATION) + return -EINVAL; + drm_modeset_acquire_init(&ctx, 0); state = drm_atomic_state_alloc(plane->dev); @@ -1216,11 +1257,28 @@ int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data, while (1) { plane_state = drm_atomic_get_plane_state(state, plane); ret = PTR_ERR_OR_ZERO(plane_state); - if (!ret) { - to_intel_plane_state(plane_state)->ckey = *set; - ret = drm_atomic_commit(state); + if (!ret) + intel_plane_set_ckey(to_intel_plane_state(plane_state), set); + + /* + * On some platforms we have to configure + * the dst colorkey on the primary plane. + */ + if (!ret && has_dst_key_in_primary_plane(dev_priv)) { + struct intel_crtc *crtc = + intel_get_crtc_for_pipe(dev_priv, + to_intel_plane(plane)->pipe); + + plane_state = drm_atomic_get_plane_state(state, + crtc->base.primary); + ret = PTR_ERR_OR_ZERO(plane_state); + if (!ret) + intel_plane_set_ckey(to_intel_plane_state(plane_state), set); } + if (!ret) + ret = drm_atomic_commit(state); + if (ret != -EDEADLK) break; -- 2.30.2