1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2023 Intel Corporation 4 */ 5 6 #include "i915_drv.h" 7 #include "intel_crtc.h" 8 #include "intel_display_types.h" 9 #include "intel_sprite_uapi.h" 10 11 static bool has_dst_key_in_primary_plane(struct drm_i915_private *dev_priv) 12 { 13 return DISPLAY_VER(dev_priv) >= 9; 14 } 15 16 static void intel_plane_set_ckey(struct intel_plane_state *plane_state, 17 const struct drm_intel_sprite_colorkey *set) 18 { 19 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); 20 struct drm_i915_private *dev_priv = to_i915(plane->base.dev); 21 struct drm_intel_sprite_colorkey *key = &plane_state->ckey; 22 23 *key = *set; 24 25 /* 26 * We want src key enabled on the 27 * sprite and not on the primary. 28 */ 29 if (plane->id == PLANE_PRIMARY && 30 set->flags & I915_SET_COLORKEY_SOURCE) 31 key->flags = 0; 32 33 /* 34 * On SKL+ we want dst key enabled on 35 * the primary and not on the sprite. 36 */ 37 if (DISPLAY_VER(dev_priv) >= 9 && plane->id != PLANE_PRIMARY && 38 set->flags & I915_SET_COLORKEY_DESTINATION) 39 key->flags = 0; 40 } 41 42 int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data, 43 struct drm_file *file_priv) 44 { 45 struct drm_i915_private *dev_priv = to_i915(dev); 46 struct drm_intel_sprite_colorkey *set = data; 47 struct drm_plane *plane; 48 struct drm_plane_state *plane_state; 49 struct drm_atomic_state *state; 50 struct drm_modeset_acquire_ctx ctx; 51 int ret = 0; 52 53 /* ignore the pointless "none" flag */ 54 set->flags &= ~I915_SET_COLORKEY_NONE; 55 56 if (set->flags & ~(I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) 57 return -EINVAL; 58 59 /* Make sure we don't try to enable both src & dest simultaneously */ 60 if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) 61 return -EINVAL; 62 63 if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && 64 set->flags & I915_SET_COLORKEY_DESTINATION) 65 return -EINVAL; 66 67 plane = drm_plane_find(dev, file_priv, set->plane_id); 68 if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) 69 return -ENOENT; 70 71 /* 72 * SKL+ only plane 2 can do destination keying against plane 1. 73 * Also multiple planes can't do destination keying on the same 74 * pipe simultaneously. 75 */ 76 if (DISPLAY_VER(dev_priv) >= 9 && 77 to_intel_plane(plane)->id >= PLANE_3 && 78 set->flags & I915_SET_COLORKEY_DESTINATION) 79 return -EINVAL; 80 81 drm_modeset_acquire_init(&ctx, 0); 82 83 state = drm_atomic_state_alloc(plane->dev); 84 if (!state) { 85 ret = -ENOMEM; 86 goto out; 87 } 88 state->acquire_ctx = &ctx; 89 to_intel_atomic_state(state)->internal = true; 90 91 while (1) { 92 plane_state = drm_atomic_get_plane_state(state, plane); 93 ret = PTR_ERR_OR_ZERO(plane_state); 94 if (!ret) 95 intel_plane_set_ckey(to_intel_plane_state(plane_state), set); 96 97 /* 98 * On some platforms we have to configure 99 * the dst colorkey on the primary plane. 100 */ 101 if (!ret && has_dst_key_in_primary_plane(dev_priv)) { 102 struct intel_crtc *crtc = 103 intel_crtc_for_pipe(dev_priv, 104 to_intel_plane(plane)->pipe); 105 106 plane_state = drm_atomic_get_plane_state(state, 107 crtc->base.primary); 108 ret = PTR_ERR_OR_ZERO(plane_state); 109 if (!ret) 110 intel_plane_set_ckey(to_intel_plane_state(plane_state), set); 111 } 112 113 if (!ret) 114 ret = drm_atomic_commit(state); 115 116 if (ret != -EDEADLK) 117 break; 118 119 drm_atomic_state_clear(state); 120 drm_modeset_backoff(&ctx); 121 } 122 123 drm_atomic_state_put(state); 124 out: 125 drm_modeset_drop_locks(&ctx); 126 drm_modeset_acquire_fini(&ctx); 127 return ret; 128 } 129