| 1 | // SPDX-License-Identifier: MIT |
| 2 | /* |
| 3 | * Copyright © 2023 Intel Corporation |
| 4 | */ |
| 5 | |
| 6 | #include "intel_crtc.h" |
| 7 | #include "intel_display_core.h" |
| 8 | #include "intel_display_types.h" |
| 9 | #include "intel_sprite_uapi.h" |
| 10 | |
| 11 | static bool has_dst_key_in_primary_plane(struct intel_display *display) |
| 12 | { |
| 13 | return DISPLAY_VER(display) >= 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_display *display = to_intel_display(plane_state); |
| 20 | struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); |
| 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(display) >= 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_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 ((display->platform.valleyview || display->platform.cherryview) && |
| 64 | set->flags & I915_SET_COLORKEY_DESTINATION) |
| 65 | return -EINVAL; |
| 66 | |
| 67 | plane = drm_plane_find(dev, file_priv, id: 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(display) >= 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: &ctx, flags: 0); |
| 82 | |
| 83 | state = drm_atomic_state_alloc(dev: 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(ptr: 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(display)) { |
| 102 | struct intel_crtc *crtc = |
| 103 | intel_crtc_for_pipe(display, |
| 104 | to_intel_plane(plane)->pipe); |
| 105 | |
| 106 | plane_state = drm_atomic_get_plane_state(state, |
| 107 | plane: crtc->base.primary); |
| 108 | ret = PTR_ERR_OR_ZERO(ptr: 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: &ctx); |
| 121 | } |
| 122 | |
| 123 | drm_atomic_state_put(state); |
| 124 | out: |
| 125 | drm_modeset_drop_locks(ctx: &ctx); |
| 126 | drm_modeset_acquire_fini(ctx: &ctx); |
| 127 | return ret; |
| 128 | } |
| 129 | |