| 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 |  | 
|---|