@@ -6000,8 +6000,8 @@ enum {
#define DISPPLANE_SEL_PIPE_SHIFT 24
#define DISPPLANE_SEL_PIPE_MASK (3<<DISPPLANE_SEL_PIPE_SHIFT)
#define DISPPLANE_SEL_PIPE(pipe) ((pipe)<<DISPPLANE_SEL_PIPE_SHIFT)
+#define DISPPLANE_SRC_KEY_WINDOW_ENABLE (1<<23) /* planes A/B */
#define DISPPLANE_SRC_KEY_ENABLE (1<<22)
-#define DISPPLANE_SRC_KEY_DISABLE 0
#define DISPPLANE_LINE_DOUBLE (1<<20)
#define DISPPLANE_NO_LINE_DOUBLE 0
#define DISPPLANE_STEREO_POLARITY_FIRST 0
@@ -6014,8 +6014,12 @@ enum {
#define _DSPAADDR 0x70184
#define _DSPASTRIDE 0x70188
#define _DSPAPOS 0x7018C /* reserved */
+#define _DSPAKEYVAL 0x70194 /* planes A/B */
+#define _DSPAMINKEYVAL 0x70194 /* plane C */
+#define _DSPAKEYMSK 0x70198
#define _DSPASIZE 0x70190
#define _DSPASURF 0x7019C /* 965+ only */
+#define _DSPAMAXKEYVAL 0x701A0 /* plane C */
#define _DSPATILEOFF 0x701A4 /* 965+ only */
#define _DSPAOFFSET 0x701A4 /* HSW */
#define _DSPASURFLIVE 0x701AC
@@ -6024,6 +6028,9 @@ enum {
#define DSPADDR(plane) _MMIO_PIPE2(plane, _DSPAADDR)
#define DSPSTRIDE(plane) _MMIO_PIPE2(plane, _DSPASTRIDE)
#define DSPPOS(plane) _MMIO_PIPE2(plane, _DSPAPOS)
+#define DSPKEYVAL(plane) _MMIO_PIPE2(plane, _DSPAKEYVAL)
+#define DSPMINKEYVAL(plane) _MMIO_PIPE2(plane, _DSPAMINKEYVAL)
+#define DSPKEYMSK(plane) _MMIO_PIPE2(plane, _DSPAKEYMSK)
#define DSPSIZE(plane) _MMIO_PIPE2(plane, _DSPASIZE)
#define DSPSURF(plane) _MMIO_PIPE2(plane, _DSPASURF)
#define DSPTILEOFF(plane) _MMIO_PIPE2(plane, _DSPATILEOFF)
@@ -200,6 +200,9 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_
*/
crtc_state->raw_zpos[intel_plane->id] =
intel_plane_raw_zpos(crtc_state, intel_state);
+ crtc_state->raw_dst_colorkey[intel_plane->id] =
+ intel_state->base.visible &&
+ intel_state->ckey.flags & I915_SET_COLORKEY_DESTINATION;
return intel_plane_atomic_calc_changes(old_crtc_state,
&crtc_state->base,
@@ -3314,6 +3314,7 @@ static void i9xx_update_plane(struct intel_plane *plane,
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
const struct drm_framebuffer *fb = plane_state->base.fb;
enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
+ const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
u32 linear_offset;
u32 dspcntr = plane_state->ctl;
i915_reg_t reg = DSPCNTR(i9xx_plane);
@@ -3329,8 +3330,17 @@ static void i9xx_update_plane(struct intel_plane *plane,
else
dspaddr_offset = linear_offset;
+ if (crtc_state->dst_colorkey[plane->id])
+ dspcntr |= DISPPLANE_SRC_KEY_ENABLE |
+ DISPPLANE_SRC_KEY_WINDOW_ENABLE;
+
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+ if (crtc_state->dst_colorkey[plane->id]) {
+ I915_WRITE_FW(DSPKEYVAL(i9xx_plane), key->min_value);
+ I915_WRITE_FW(DSPKEYMSK(i9xx_plane), key->channel_mask);
+ }
+
if (INTEL_GEN(dev_priv) < 4) {
/* pipesrc and dspsize control the size that is scaled from,
* which should always be the user's requested size.
@@ -10936,6 +10946,7 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
struct intel_shared_dpll *shared_dpll;
struct intel_crtc_wm_state wm_state;
u8 raw_zpos[I915_MAX_PLANES];
+ u8 raw_dst_colorkey[I915_MAX_PLANES];
bool force_thru, ips_force_disable;
/* FIXME: before the switch to atomic started, a new pipe_config was
@@ -10952,6 +10963,7 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
wm_state = crtc_state->wm;
memcpy(raw_zpos, crtc_state->raw_zpos, sizeof(raw_zpos));
+ memcpy(raw_dst_colorkey, crtc_state->raw_dst_colorkey, sizeof(raw_dst_colorkey));
/* Keep base drm_crtc_state intact, only clear our extended struct */
BUILD_BUG_ON(offsetof(struct intel_crtc_state, base));
@@ -10967,6 +10979,7 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
crtc_state->wm = wm_state;
memcpy(crtc_state->raw_zpos, raw_zpos, sizeof(raw_zpos));
+ memcpy(crtc_state->raw_dst_colorkey, raw_dst_colorkey, sizeof(raw_dst_colorkey));
}
static int
@@ -12242,6 +12255,55 @@ static void vlv_normalize_zpos(struct intel_crtc_state *crtc_state)
}
}
+static int vlv_fixup_colorkey_zpos(struct intel_crtc_state *crtc_state)
+{
+ /* disable dst colorkey if the primary is above the sprite */
+ crtc_state->dst_colorkey[PLANE_SPRITE0] =
+ crtc_state->raw_dst_colorkey[PLANE_SPRITE0] &&
+ crtc_state->zpos[PLANE_SPRITE0] > crtc_state->zpos[PLANE_PRIMARY];
+
+ crtc_state->dst_colorkey[PLANE_SPRITE1] =
+ crtc_state->raw_dst_colorkey[PLANE_SPRITE1] &&
+ crtc_state->zpos[PLANE_SPRITE1] > crtc_state->zpos[PLANE_PRIMARY];
+
+ /* lift the primary above the sprites that have dst colorkey enabled */
+ if (crtc_state->dst_colorkey[PLANE_SPRITE0] &&
+ crtc_state->dst_colorkey[PLANE_SPRITE1]) {
+ /*
+ * FIXME should make sure both planes have
+ * the same dst colorkey value+mask.
+ */
+ crtc_state->zpos[PLANE_SPRITE0]--;
+ crtc_state->zpos[PLANE_SPRITE1]--;
+ crtc_state->zpos[PLANE_PRIMARY] = 2;
+ } else if (crtc_state->dst_colorkey[PLANE_SPRITE0]) {
+ if (crtc_state->zpos[PLANE_SPRITE1] <
+ crtc_state->zpos[PLANE_SPRITE0]) {
+ DRM_DEBUG_KMS("Sprite 0 dst colorkey conflicts with zpos\n");
+ return -EINVAL;
+ }
+
+ swap(crtc_state->zpos[PLANE_PRIMARY],
+ crtc_state->zpos[PLANE_SPRITE0]);
+ } else if (crtc_state->dst_colorkey[PLANE_SPRITE1]) {
+ if (crtc_state->zpos[PLANE_SPRITE0] <
+ crtc_state->zpos[PLANE_SPRITE1]) {
+ DRM_DEBUG_KMS("Sprite 1 dst colorkey conflicts with zpos\n");
+ return -EINVAL;
+ }
+
+ swap(crtc_state->zpos[PLANE_PRIMARY],
+ crtc_state->zpos[PLANE_SPRITE1]);
+ }
+
+ /* enable the dst colorkey on the primary if either sprite needs it */
+ crtc_state->dst_colorkey[PLANE_PRIMARY] =
+ crtc_state->dst_colorkey[PLANE_SPRITE0] ||
+ crtc_state->dst_colorkey[PLANE_SPRITE1];
+
+ return 0;
+}
+
static int vlv_update_zpos(struct drm_i915_private *dev_priv,
struct intel_atomic_state *state)
{
@@ -12251,16 +12313,26 @@ static int vlv_update_zpos(struct drm_i915_private *dev_priv,
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
struct drm_plane *plane;
+ bool primary_changed;
bool sprites_changed;
+ int ret;
vlv_normalize_zpos(new_crtc_state);
+ ret = vlv_fixup_colorkey_zpos(new_crtc_state);
+ if (ret)
+ return ret;
+
+ primary_changed =
+ new_crtc_state->dst_colorkey[PLANE_PRIMARY] !=
+ old_crtc_state->dst_colorkey[PLANE_PRIMARY];
+
sprites_changed =
memcmp(new_crtc_state->zpos,
old_crtc_state->zpos,
sizeof(new_crtc_state->zpos)) != 0;
- if (!sprites_changed)
+ if (!primary_changed && !sprites_changed)
continue;
drm_for_each_plane_mask(plane, &dev_priv->drm,
@@ -12268,14 +12340,23 @@ static int vlv_update_zpos(struct drm_i915_private *dev_priv,
struct drm_plane_state *plane_state;
enum plane_id plane_id = to_intel_plane(plane)->id;
- if (plane_id == PLANE_CURSOR ||
- plane_id == PLANE_PRIMARY)
+ if (plane_id == PLANE_CURSOR)
continue;
+ if (plane_id == PLANE_PRIMARY) {
+ if (!primary_changed)
+ continue;
+ } else {
+ if (!sprites_changed)
+ continue;
+ }
+
/*
* zpos is configured via sprite registers, so must
* add them to the state if anything significant
- * changed.
+ * changed. dst colorkeying is configured via the primary
+ * plane registers, so similarly we may need to reconfigure
+ * it as well.
*/
plane_state = drm_atomic_get_plane_state(&state->base, plane);
if (IS_ERR(plane_state))
@@ -894,6 +894,9 @@ struct intel_crtc_state {
u8 raw_zpos[I915_MAX_PLANES]; /* raw property value (or 0xff for disabled planes) */
u8 zpos[I915_MAX_PLANES]; /* final zpos for each plane */
+ u8 raw_dst_colorkey[I915_MAX_PLANES]; /* dst colorkey yes/no? */
+ u8 dst_colorkey[I915_MAX_PLANES]; /* dst colorkey yes/no? */
+
/* HDMI scrambling status */
bool hdmi_scrambling;
@@ -564,7 +564,7 @@ vlv_update_plane(struct intel_plane *plane,
if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B)
chv_update_csc(plane_state);
- if (key->flags) {
+ if (key->flags & I915_SET_COLORKEY_SOURCE) {
I915_WRITE_FW(SPKEYMINVAL(pipe, plane_id), key->min_value);
I915_WRITE_FW(SPKEYMAXVAL(pipe, plane_id), key->max_value);
I915_WRITE_FW(SPKEYMSK(pipe, plane_id), key->channel_mask >> 24);
@@ -1092,13 +1092,15 @@ intel_check_sprite_plane(struct intel_plane *plane,
static bool has_dst_key_in_primary_plane(struct drm_i915_private *dev_priv)
{
- return INTEL_GEN(dev_priv) >= 9;
+ return INTEL_GEN(dev_priv) >= 9 ||
+ IS_CHERRYVIEW(dev_priv) || IS_VALLEYVIEW(dev_priv);
}
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;
@@ -1114,8 +1116,13 @@ static void intel_plane_set_ckey(struct intel_plane_state *plane_state,
/*
* On SKL+ we want dst key enabled on
* the primary and not on the sprite.
+ *
+ * On VLV/CHV we want to keep the dst key flag even on the
+ * sprites to make the crtc_state->dst_colorkey[] stuff work.
+ * vlv_update_plane() won't do anything with the dst key flag
+ * anyway, so leaving it on doesn't hurt.
*/
- if (plane->id != PLANE_PRIMARY &&
+ if (INTEL_GEN(dev_priv) >= 9 && plane->id != PLANE_PRIMARY &&
set->flags & I915_SET_COLORKEY_DESTINATION)
key->flags = 0;
}
@@ -1141,10 +1148,6 @@ int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data,
if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
return -EINVAL;
- if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
- set->flags & I915_SET_COLORKEY_DESTINATION)
- return -EINVAL;
-
plane = drm_plane_find(dev, file_priv, set->plane_id);
if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY)
return -ENOENT;
@@ -1177,6 +1180,10 @@ int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data,
/*
* On some platforms we have to configure
* the dst colorkey on the primary plane.
+ *
+ * FIXME this won't work properly for multiple
+ * sprite planes on VLV/CHV if each is trying to
+ * use a different colorkey value/mask.
*/
if (!ret && has_dst_key_in_primary_plane(dev_priv)) {
struct intel_crtc *crtc =