1 // SPDX-License-Identifier: GPL-2.0+
2
3 #include "vkms_config.h"
4 #include <linux/iosys-map.h>
5
6 #include <drm/drm_atomic.h>
7 #include <drm/drm_atomic_helper.h>
8 #include <drm/drm_blend.h>
9 #include <drm/drm_fourcc.h>
10 #include <drm/drm_gem_atomic_helper.h>
11 #include <drm/drm_gem_framebuffer_helper.h>
12 #include <drm/drm_print.h>
13
14 #include "vkms_drv.h"
15 #include "vkms_formats.h"
16
17 static const u32 vkms_formats[] = {
18 DRM_FORMAT_ARGB8888,
19 DRM_FORMAT_ABGR8888,
20 DRM_FORMAT_BGRA8888,
21 DRM_FORMAT_RGBA8888,
22 DRM_FORMAT_XRGB8888,
23 DRM_FORMAT_XBGR8888,
24 DRM_FORMAT_RGB888,
25 DRM_FORMAT_BGR888,
26 DRM_FORMAT_XRGB16161616,
27 DRM_FORMAT_XBGR16161616,
28 DRM_FORMAT_ARGB16161616,
29 DRM_FORMAT_ABGR16161616,
30 DRM_FORMAT_RGB565,
31 DRM_FORMAT_BGR565,
32 DRM_FORMAT_NV12,
33 DRM_FORMAT_NV16,
34 DRM_FORMAT_NV24,
35 DRM_FORMAT_NV21,
36 DRM_FORMAT_NV61,
37 DRM_FORMAT_NV42,
38 DRM_FORMAT_YUV420,
39 DRM_FORMAT_YUV422,
40 DRM_FORMAT_YUV444,
41 DRM_FORMAT_YVU420,
42 DRM_FORMAT_YVU422,
43 DRM_FORMAT_YVU444,
44 DRM_FORMAT_P010,
45 DRM_FORMAT_P012,
46 DRM_FORMAT_P016,
47 DRM_FORMAT_R1,
48 DRM_FORMAT_R2,
49 DRM_FORMAT_R4,
50 DRM_FORMAT_R8,
51 };
52
53 static struct drm_plane_state *
vkms_plane_duplicate_state(struct drm_plane * plane)54 vkms_plane_duplicate_state(struct drm_plane *plane)
55 {
56 struct vkms_plane_state *vkms_state;
57 struct vkms_frame_info *frame_info;
58
59 vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
60 if (!vkms_state)
61 return NULL;
62
63 frame_info = kzalloc(sizeof(*frame_info), GFP_KERNEL);
64 if (!frame_info) {
65 DRM_DEBUG_KMS("Couldn't allocate frame_info\n");
66 kfree(vkms_state);
67 return NULL;
68 }
69
70 vkms_state->frame_info = frame_info;
71
72 __drm_gem_duplicate_shadow_plane_state(plane, &vkms_state->base);
73
74 return &vkms_state->base.base;
75 }
76
vkms_plane_destroy_state(struct drm_plane * plane,struct drm_plane_state * old_state)77 static void vkms_plane_destroy_state(struct drm_plane *plane,
78 struct drm_plane_state *old_state)
79 {
80 struct vkms_plane_state *vkms_state = to_vkms_plane_state(old_state);
81 struct drm_crtc *crtc = vkms_state->base.base.crtc;
82
83 if (crtc && vkms_state->frame_info->fb) {
84 /* dropping the reference we acquired in
85 * vkms_primary_plane_update()
86 */
87 if (drm_framebuffer_read_refcount(vkms_state->frame_info->fb))
88 drm_framebuffer_put(vkms_state->frame_info->fb);
89 }
90
91 kfree(vkms_state->frame_info);
92 vkms_state->frame_info = NULL;
93
94 __drm_gem_destroy_shadow_plane_state(&vkms_state->base);
95 kfree(vkms_state);
96 }
97
vkms_plane_reset(struct drm_plane * plane)98 static void vkms_plane_reset(struct drm_plane *plane)
99 {
100 struct vkms_plane_state *vkms_state;
101
102 if (plane->state) {
103 vkms_plane_destroy_state(plane, plane->state);
104 plane->state = NULL; /* must be set to NULL here */
105 }
106
107 vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
108 if (!vkms_state) {
109 DRM_ERROR("Cannot allocate vkms_plane_state\n");
110 return;
111 }
112
113 __drm_gem_reset_shadow_plane(plane, &vkms_state->base);
114 }
115
116 static const struct drm_plane_funcs vkms_plane_funcs = {
117 .update_plane = drm_atomic_helper_update_plane,
118 .disable_plane = drm_atomic_helper_disable_plane,
119 .reset = vkms_plane_reset,
120 .atomic_duplicate_state = vkms_plane_duplicate_state,
121 .atomic_destroy_state = vkms_plane_destroy_state,
122 };
123
vkms_plane_atomic_update(struct drm_plane * plane,struct drm_atomic_state * state)124 static void vkms_plane_atomic_update(struct drm_plane *plane,
125 struct drm_atomic_state *state)
126 {
127 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
128 plane);
129 struct vkms_plane_state *vkms_plane_state;
130 struct drm_shadow_plane_state *shadow_plane_state;
131 struct drm_framebuffer *fb = new_state->fb;
132 struct vkms_frame_info *frame_info;
133 u32 fmt;
134
135 if (!new_state->crtc || !fb)
136 return;
137
138 fmt = fb->format->format;
139 vkms_plane_state = to_vkms_plane_state(new_state);
140 shadow_plane_state = &vkms_plane_state->base;
141
142 frame_info = vkms_plane_state->frame_info;
143 memcpy(&frame_info->src, &new_state->src, sizeof(struct drm_rect));
144 memcpy(&frame_info->dst, &new_state->dst, sizeof(struct drm_rect));
145 frame_info->fb = fb;
146 memcpy(&frame_info->map, &shadow_plane_state->data, sizeof(frame_info->map));
147 drm_framebuffer_get(frame_info->fb);
148 frame_info->rotation = new_state->rotation;
149
150 vkms_plane_state->pixel_read_line = get_pixel_read_line_function(fmt);
151 get_conversion_matrix_to_argb_u16(fmt, new_state->color_encoding, new_state->color_range,
152 &vkms_plane_state->conversion_matrix);
153 }
154
vkms_plane_atomic_check(struct drm_plane * plane,struct drm_atomic_state * state)155 static int vkms_plane_atomic_check(struct drm_plane *plane,
156 struct drm_atomic_state *state)
157 {
158 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
159 plane);
160 struct drm_crtc_state *crtc_state;
161 int ret;
162
163 if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc))
164 return 0;
165
166 crtc_state = drm_atomic_get_crtc_state(state,
167 new_plane_state->crtc);
168 if (IS_ERR(crtc_state))
169 return PTR_ERR(crtc_state);
170
171 ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
172 DRM_PLANE_NO_SCALING,
173 DRM_PLANE_NO_SCALING,
174 true, true);
175 if (ret != 0)
176 return ret;
177
178 return 0;
179 }
180
vkms_prepare_fb(struct drm_plane * plane,struct drm_plane_state * state)181 static int vkms_prepare_fb(struct drm_plane *plane,
182 struct drm_plane_state *state)
183 {
184 struct drm_shadow_plane_state *shadow_plane_state;
185 struct drm_framebuffer *fb = state->fb;
186 int ret;
187
188 if (!fb)
189 return 0;
190
191 shadow_plane_state = to_drm_shadow_plane_state(state);
192
193 ret = drm_gem_plane_helper_prepare_fb(plane, state);
194 if (ret)
195 return ret;
196
197 return drm_gem_fb_vmap(fb, shadow_plane_state->map, shadow_plane_state->data);
198 }
199
vkms_cleanup_fb(struct drm_plane * plane,struct drm_plane_state * state)200 static void vkms_cleanup_fb(struct drm_plane *plane,
201 struct drm_plane_state *state)
202 {
203 struct drm_shadow_plane_state *shadow_plane_state;
204 struct drm_framebuffer *fb = state->fb;
205
206 if (!fb)
207 return;
208
209 shadow_plane_state = to_drm_shadow_plane_state(state);
210
211 drm_gem_fb_vunmap(fb, shadow_plane_state->map);
212 }
213
214 static const struct drm_plane_helper_funcs vkms_plane_helper_funcs = {
215 .atomic_update = vkms_plane_atomic_update,
216 .atomic_check = vkms_plane_atomic_check,
217 .prepare_fb = vkms_prepare_fb,
218 .cleanup_fb = vkms_cleanup_fb,
219 };
220
vkms_plane_init(struct vkms_device * vkmsdev,struct vkms_config_plane * plane_cfg)221 struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
222 struct vkms_config_plane *plane_cfg)
223 {
224 struct drm_device *dev = &vkmsdev->drm;
225 struct vkms_plane *plane;
226
227 plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 0,
228 &vkms_plane_funcs,
229 vkms_formats, ARRAY_SIZE(vkms_formats),
230 NULL, vkms_config_plane_get_type(plane_cfg),
231 NULL);
232 if (IS_ERR(plane))
233 return plane;
234
235 drm_plane_helper_add(&plane->base, &vkms_plane_helper_funcs);
236
237 drm_plane_create_rotation_property(&plane->base, DRM_MODE_ROTATE_0,
238 DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK);
239
240 drm_plane_create_color_properties(&plane->base,
241 BIT(DRM_COLOR_YCBCR_BT601) |
242 BIT(DRM_COLOR_YCBCR_BT709) |
243 BIT(DRM_COLOR_YCBCR_BT2020),
244 BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
245 BIT(DRM_COLOR_YCBCR_FULL_RANGE),
246 DRM_COLOR_YCBCR_BT601,
247 DRM_COLOR_YCBCR_FULL_RANGE);
248
249 if (vkms_config_plane_get_default_pipeline(plane_cfg))
250 vkms_initialize_colorops(&plane->base);
251
252 return plane;
253 }
254