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 intel_display *display = to_intel_display(dev); 46 struct drm_i915_private *dev_priv = to_i915(dev); 47 struct drm_intel_sprite_colorkey *set = data; 48 struct drm_plane *plane; 49 struct drm_plane_state *plane_state; 50 struct drm_atomic_state *state; 51 struct drm_modeset_acquire_ctx ctx; 52 int ret = 0; 53 54 /* ignore the pointless "none" flag */ 55 set->flags &= ~I915_SET_COLORKEY_NONE; 56 57 if (set->flags & ~(I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) 58 return -EINVAL; 59 60 /* Make sure we don't try to enable both src & dest simultaneously */ 61 if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) 62 return -EINVAL; 63 64 if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && 65 set->flags & I915_SET_COLORKEY_DESTINATION) 66 return -EINVAL; 67 68 plane = drm_plane_find(dev, file_priv, set->plane_id); 69 if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) 70 return -ENOENT; 71 72 /* 73 * SKL+ only plane 2 can do destination keying against plane 1. 74 * Also multiple planes can't do destination keying on the same 75 * pipe simultaneously. 76 */ 77 if (DISPLAY_VER(dev_priv) >= 9 && 78 to_intel_plane(plane)->id >= PLANE_3 && 79 set->flags & I915_SET_COLORKEY_DESTINATION) 80 return -EINVAL; 81 82 drm_modeset_acquire_init(&ctx, 0); 83 84 state = drm_atomic_state_alloc(plane->dev); 85 if (!state) { 86 ret = -ENOMEM; 87 goto out; 88 } 89 state->acquire_ctx = &ctx; 90 to_intel_atomic_state(state)->internal = true; 91 92 while (1) { 93 plane_state = drm_atomic_get_plane_state(state, plane); 94 ret = PTR_ERR_OR_ZERO(plane_state); 95 if (!ret) 96 intel_plane_set_ckey(to_intel_plane_state(plane_state), set); 97 98 /* 99 * On some platforms we have to configure 100 * the dst colorkey on the primary plane. 101 */ 102 if (!ret && has_dst_key_in_primary_plane(dev_priv)) { 103 struct intel_crtc *crtc = 104 intel_crtc_for_pipe(display, 105 to_intel_plane(plane)->pipe); 106 107 plane_state = drm_atomic_get_plane_state(state, 108 crtc->base.primary); 109 ret = PTR_ERR_OR_ZERO(plane_state); 110 if (!ret) 111 intel_plane_set_ckey(to_intel_plane_state(plane_state), set); 112 } 113 114 if (!ret) 115 ret = drm_atomic_commit(state); 116 117 if (ret != -EDEADLK) 118 break; 119 120 drm_atomic_state_clear(state); 121 drm_modeset_backoff(&ctx); 122 } 123 124 drm_atomic_state_put(state); 125 out: 126 drm_modeset_drop_locks(&ctx); 127 drm_modeset_acquire_fini(&ctx); 128 return ret; 129 } 130