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(dev: 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, 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(dev_priv) >= 9 && |
77 | to_intel_plane(plane)->id >= PLANE_SPRITE1 && |
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(dev_priv)) { |
102 | struct intel_crtc *crtc = |
103 | intel_crtc_for_pipe(i915: dev_priv, |
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 | |