1 /*
2 * Copyright (C) 2015 Red Hat, Inc.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26 #include <drm/drm_atomic_helper.h>
27 #include <drm/drm_blend.h>
28 #include <drm/drm_damage_helper.h>
29 #include <drm/drm_fourcc.h>
30 #include <drm/drm_gem_atomic_helper.h>
31 #include <linux/virtio_dma_buf.h>
32 #include <drm/drm_managed.h>
33 #include <drm/drm_panic.h>
34 #include <drm/drm_print.h>
35
36 #include "virtgpu_drv.h"
37
38 static const uint32_t virtio_gpu_formats[] = {
39 DRM_FORMAT_HOST_XRGB8888,
40 };
41
42 static const uint32_t virtio_gpu_cursor_formats[] = {
43 DRM_FORMAT_HOST_ARGB8888,
44 };
45
virtio_gpu_translate_format(uint32_t drm_fourcc)46 uint32_t virtio_gpu_translate_format(uint32_t drm_fourcc)
47 {
48 uint32_t format;
49
50 switch (drm_fourcc) {
51 case DRM_FORMAT_XRGB8888:
52 format = VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM;
53 break;
54 case DRM_FORMAT_ARGB8888:
55 format = VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM;
56 break;
57 case DRM_FORMAT_BGRX8888:
58 format = VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM;
59 break;
60 case DRM_FORMAT_BGRA8888:
61 format = VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM;
62 break;
63 default:
64 /*
65 * This should not happen, we handle everything listed
66 * in virtio_gpu_formats[].
67 */
68 format = 0;
69 break;
70 }
71 WARN_ON(format == 0);
72 return format;
73 }
74
75 static struct
virtio_gpu_plane_duplicate_state(struct drm_plane * plane)76 drm_plane_state *virtio_gpu_plane_duplicate_state(struct drm_plane *plane)
77 {
78 struct virtio_gpu_plane_state *new;
79
80 if (WARN_ON(!plane->state))
81 return NULL;
82
83 new = kzalloc_obj(*new);
84 if (!new)
85 return NULL;
86
87 __drm_atomic_helper_plane_duplicate_state(plane, &new->base);
88
89 return &new->base;
90 }
91
92 static const struct drm_plane_funcs virtio_gpu_plane_funcs = {
93 .update_plane = drm_atomic_helper_update_plane,
94 .disable_plane = drm_atomic_helper_disable_plane,
95 .reset = drm_atomic_helper_plane_reset,
96 .atomic_duplicate_state = virtio_gpu_plane_duplicate_state,
97 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
98 };
99
virtio_gpu_plane_atomic_check(struct drm_plane * plane,struct drm_atomic_commit * state)100 static int virtio_gpu_plane_atomic_check(struct drm_plane *plane,
101 struct drm_atomic_commit *state)
102 {
103 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
104 plane);
105 struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state,
106 plane);
107 bool is_cursor = plane->type == DRM_PLANE_TYPE_CURSOR;
108 struct drm_crtc_state *crtc_state;
109 int ret;
110
111 if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc))
112 return 0;
113
114 /*
115 * Ignore damage clips if the framebuffer attached to the plane's state
116 * has changed since the last plane update (page-flip). In this case, a
117 * full plane update should happen because uploads are done per-buffer.
118 */
119 if (old_plane_state->fb != new_plane_state->fb)
120 new_plane_state->ignore_damage_clips = true;
121
122 crtc_state = drm_atomic_get_crtc_state(state,
123 new_plane_state->crtc);
124 if (IS_ERR(crtc_state))
125 return PTR_ERR(crtc_state);
126
127 ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
128 DRM_PLANE_NO_SCALING,
129 DRM_PLANE_NO_SCALING,
130 is_cursor, true);
131 return ret;
132 }
133
134 /* For drm panic */
virtio_gpu_panic_update_dumb_bo(struct virtio_gpu_device * vgdev,struct drm_plane_state * state,struct drm_rect * rect)135 static int virtio_gpu_panic_update_dumb_bo(struct virtio_gpu_device *vgdev,
136 struct drm_plane_state *state,
137 struct drm_rect *rect)
138 {
139 struct virtio_gpu_object *bo =
140 gem_to_virtio_gpu_obj(state->fb->obj[0]);
141 struct virtio_gpu_object_array *objs;
142 uint32_t w = rect->x2 - rect->x1;
143 uint32_t h = rect->y2 - rect->y1;
144 uint32_t x = rect->x1;
145 uint32_t y = rect->y1;
146 uint32_t off = x * state->fb->format->cpp[0] +
147 y * state->fb->pitches[0];
148
149 objs = virtio_gpu_panic_array_alloc();
150 if (!objs)
151 return -ENOMEM;
152 virtio_gpu_array_add_obj(objs, &bo->base.base);
153
154 return virtio_gpu_panic_cmd_transfer_to_host_2d(vgdev, off, w, h, x, y,
155 objs);
156 }
157
virtio_gpu_update_dumb_bo(struct virtio_gpu_device * vgdev,struct drm_plane_state * state,struct drm_rect * rect)158 static void virtio_gpu_update_dumb_bo(struct virtio_gpu_device *vgdev,
159 struct drm_plane_state *state,
160 struct drm_rect *rect)
161 {
162 struct virtio_gpu_object *bo =
163 gem_to_virtio_gpu_obj(state->fb->obj[0]);
164 struct virtio_gpu_object_array *objs;
165 uint32_t w = rect->x2 - rect->x1;
166 uint32_t h = rect->y2 - rect->y1;
167 uint32_t x = rect->x1;
168 uint32_t y = rect->y1;
169 uint32_t off = x * state->fb->format->cpp[0] +
170 y * state->fb->pitches[0];
171
172 objs = virtio_gpu_array_alloc(1);
173 if (!objs)
174 return;
175 virtio_gpu_array_add_obj(objs, &bo->base.base);
176
177 virtio_gpu_cmd_transfer_to_host_2d(vgdev, off, w, h, x, y,
178 objs, NULL);
179 }
180
181 /* For drm_panic */
virtio_gpu_panic_resource_flush(struct drm_plane * plane,uint32_t x,uint32_t y,uint32_t width,uint32_t height)182 static void virtio_gpu_panic_resource_flush(struct drm_plane *plane,
183 uint32_t x, uint32_t y,
184 uint32_t width, uint32_t height)
185 {
186 struct drm_device *dev = plane->dev;
187 struct virtio_gpu_device *vgdev = dev->dev_private;
188 struct virtio_gpu_framebuffer *vgfb;
189 struct virtio_gpu_object *bo;
190
191 vgfb = to_virtio_gpu_framebuffer(plane->state->fb);
192 bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
193
194 virtio_gpu_panic_cmd_resource_flush(vgdev, bo->hw_res_handle, x, y,
195 width, height);
196 virtio_gpu_panic_notify(vgdev);
197 }
198
virtio_gpu_resource_flush(struct drm_plane * plane,uint32_t x,uint32_t y,uint32_t width,uint32_t height)199 static void virtio_gpu_resource_flush(struct drm_plane *plane,
200 uint32_t x, uint32_t y,
201 uint32_t width, uint32_t height)
202 {
203 struct drm_device *dev = plane->dev;
204 struct virtio_gpu_device *vgdev = dev->dev_private;
205 struct virtio_gpu_framebuffer *vgfb;
206 struct virtio_gpu_plane_state *vgplane_st;
207 struct virtio_gpu_object *bo;
208
209 vgfb = to_virtio_gpu_framebuffer(plane->state->fb);
210 vgplane_st = to_virtio_gpu_plane_state(plane->state);
211 bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
212 if (vgplane_st->fence) {
213 struct virtio_gpu_object_array *objs;
214
215 objs = virtio_gpu_array_alloc(1);
216 if (!objs)
217 return;
218 virtio_gpu_array_add_obj(objs, vgfb->base.obj[0]);
219 if (virtio_gpu_lock_one_resv_uninterruptible(objs)) {
220 virtio_gpu_array_put_free(objs);
221 return;
222 }
223 virtio_gpu_cmd_resource_flush(vgdev, bo->hw_res_handle, x, y,
224 width, height, objs,
225 vgplane_st->fence);
226 virtio_gpu_notify(vgdev);
227 dma_fence_wait_timeout(&vgplane_st->fence->f, true,
228 msecs_to_jiffies(50));
229 } else {
230 virtio_gpu_cmd_resource_flush(vgdev, bo->hw_res_handle, x, y,
231 width, height, NULL, NULL);
232 virtio_gpu_notify(vgdev);
233 }
234 }
235
virtio_gpu_primary_plane_update(struct drm_plane * plane,struct drm_atomic_commit * state)236 static void virtio_gpu_primary_plane_update(struct drm_plane *plane,
237 struct drm_atomic_commit *state)
238 {
239 struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
240 plane);
241 struct drm_device *dev = plane->dev;
242 struct virtio_gpu_device *vgdev = dev->dev_private;
243 struct virtio_gpu_output *output = NULL;
244 struct virtio_gpu_object *bo;
245 struct drm_rect rect;
246
247 if (plane->state->crtc)
248 output = drm_crtc_to_virtio_gpu_output(plane->state->crtc);
249 if (old_state->crtc)
250 output = drm_crtc_to_virtio_gpu_output(old_state->crtc);
251 if (WARN_ON(!output))
252 return;
253
254 if (!plane->state->fb || !output->crtc.state->active) {
255 DRM_DEBUG("nofb\n");
256 virtio_gpu_cmd_set_scanout(vgdev, output->index, 0,
257 plane->state->src_w >> 16,
258 plane->state->src_h >> 16,
259 0, 0);
260 virtio_gpu_notify(vgdev);
261 return;
262 }
263
264 if (!drm_atomic_helper_damage_merged(old_state, plane->state, &rect))
265 return;
266
267 bo = gem_to_virtio_gpu_obj(plane->state->fb->obj[0]);
268 if (bo->dumb)
269 virtio_gpu_update_dumb_bo(vgdev, plane->state, &rect);
270
271 if (plane->state->fb != old_state->fb ||
272 plane->state->src_w != old_state->src_w ||
273 plane->state->src_h != old_state->src_h ||
274 plane->state->src_x != old_state->src_x ||
275 plane->state->src_y != old_state->src_y ||
276 output->needs_modeset) {
277 output->needs_modeset = false;
278 DRM_DEBUG("handle 0x%x, crtc %dx%d+%d+%d, src %dx%d+%d+%d\n",
279 bo->hw_res_handle,
280 plane->state->crtc_w, plane->state->crtc_h,
281 plane->state->crtc_x, plane->state->crtc_y,
282 plane->state->src_w >> 16,
283 plane->state->src_h >> 16,
284 plane->state->src_x >> 16,
285 plane->state->src_y >> 16);
286
287 if (bo->host3d_blob || bo->guest_blob) {
288 virtio_gpu_cmd_set_scanout_blob
289 (vgdev, output->index, bo,
290 plane->state->fb,
291 plane->state->src_w >> 16,
292 plane->state->src_h >> 16,
293 plane->state->src_x >> 16,
294 plane->state->src_y >> 16);
295 } else {
296 virtio_gpu_cmd_set_scanout(vgdev, output->index,
297 bo->hw_res_handle,
298 plane->state->src_w >> 16,
299 plane->state->src_h >> 16,
300 plane->state->src_x >> 16,
301 plane->state->src_y >> 16);
302 }
303 }
304
305 virtio_gpu_resource_flush(plane,
306 rect.x1,
307 rect.y1,
308 rect.x2 - rect.x1,
309 rect.y2 - rect.y1);
310 }
311
virtio_gpu_prepare_imported_obj(struct drm_plane * plane,struct drm_plane_state * new_state,struct drm_gem_object * obj)312 static int virtio_gpu_prepare_imported_obj(struct drm_plane *plane,
313 struct drm_plane_state *new_state,
314 struct drm_gem_object *obj)
315 {
316 struct virtio_gpu_device *vgdev = plane->dev->dev_private;
317 struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj);
318 struct dma_buf_attachment *attach = obj->import_attach;
319 struct dma_resv *resv = attach->dmabuf->resv;
320 struct virtio_gpu_mem_entry *ents = NULL;
321 unsigned int nents;
322 int ret;
323
324 dma_resv_lock(resv, NULL);
325
326 ret = dma_buf_pin(attach);
327 if (ret) {
328 dma_resv_unlock(resv);
329 return ret;
330 }
331
332 if (!bo->sgt) {
333 ret = virtgpu_dma_buf_import_sgt(&ents, &nents,
334 bo, attach);
335 if (ret)
336 goto err;
337
338 virtio_gpu_object_attach(vgdev, bo, ents, nents);
339 }
340
341 dma_resv_unlock(resv);
342 return 0;
343
344 err:
345 dma_buf_unpin(attach);
346 dma_resv_unlock(resv);
347 return ret;
348 }
349
virtio_gpu_plane_prepare_fb(struct drm_plane * plane,struct drm_plane_state * new_state)350 static int virtio_gpu_plane_prepare_fb(struct drm_plane *plane,
351 struct drm_plane_state *new_state)
352 {
353 struct drm_device *dev = plane->dev;
354 struct virtio_gpu_device *vgdev = dev->dev_private;
355 struct virtio_gpu_framebuffer *vgfb;
356 struct virtio_gpu_plane_state *vgplane_st;
357 struct virtio_gpu_object *bo;
358 struct drm_gem_object *obj;
359 int ret;
360
361 if (!new_state->fb)
362 return 0;
363
364 vgfb = to_virtio_gpu_framebuffer(new_state->fb);
365 vgplane_st = to_virtio_gpu_plane_state(new_state);
366 bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
367
368 drm_gem_plane_helper_prepare_fb(plane, new_state);
369
370 if (!bo || (plane->type == DRM_PLANE_TYPE_PRIMARY && !bo->guest_blob))
371 return 0;
372
373 obj = new_state->fb->obj[0];
374 if (bo->dumb || drm_gem_is_imported(obj)) {
375 vgplane_st->fence = virtio_gpu_fence_alloc(vgdev,
376 vgdev->fence_drv.context,
377 0);
378 if (!vgplane_st->fence)
379 return -ENOMEM;
380 }
381
382 if (drm_gem_is_imported(obj)) {
383 ret = virtio_gpu_prepare_imported_obj(plane, new_state, obj);
384 if (ret)
385 goto err_fence;
386 }
387
388 return 0;
389
390 err_fence:
391 if (vgplane_st->fence) {
392 dma_fence_put(&vgplane_st->fence->f);
393 vgplane_st->fence = NULL;
394 }
395
396 return ret;
397 }
398
virtio_gpu_cleanup_imported_obj(struct drm_gem_object * obj)399 static void virtio_gpu_cleanup_imported_obj(struct drm_gem_object *obj)
400 {
401 struct dma_buf_attachment *attach = obj->import_attach;
402 struct dma_resv *resv = attach->dmabuf->resv;
403
404 dma_resv_lock(resv, NULL);
405 dma_buf_unpin(attach);
406 dma_resv_unlock(resv);
407 }
408
virtio_gpu_plane_cleanup_fb(struct drm_plane * plane,struct drm_plane_state * state)409 static void virtio_gpu_plane_cleanup_fb(struct drm_plane *plane,
410 struct drm_plane_state *state)
411 {
412 struct virtio_gpu_plane_state *vgplane_st;
413 struct drm_gem_object *obj;
414
415 if (!state->fb)
416 return;
417
418 vgplane_st = to_virtio_gpu_plane_state(state);
419 if (vgplane_st->fence) {
420 dma_fence_put(&vgplane_st->fence->f);
421 vgplane_st->fence = NULL;
422 }
423
424 obj = state->fb->obj[0];
425 if (drm_gem_is_imported(obj))
426 virtio_gpu_cleanup_imported_obj(obj);
427 }
428
virtio_gpu_cursor_plane_update(struct drm_plane * plane,struct drm_atomic_commit * state)429 static void virtio_gpu_cursor_plane_update(struct drm_plane *plane,
430 struct drm_atomic_commit *state)
431 {
432 struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
433 plane);
434 struct drm_device *dev = plane->dev;
435 struct virtio_gpu_device *vgdev = dev->dev_private;
436 struct virtio_gpu_output *output = NULL;
437 struct virtio_gpu_framebuffer *vgfb;
438 struct virtio_gpu_plane_state *vgplane_st;
439 struct virtio_gpu_object *bo = NULL;
440 uint32_t handle;
441
442 if (plane->state->crtc)
443 output = drm_crtc_to_virtio_gpu_output(plane->state->crtc);
444 if (old_state->crtc)
445 output = drm_crtc_to_virtio_gpu_output(old_state->crtc);
446 if (WARN_ON(!output))
447 return;
448
449 if (plane->state->fb) {
450 vgfb = to_virtio_gpu_framebuffer(plane->state->fb);
451 vgplane_st = to_virtio_gpu_plane_state(plane->state);
452 bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
453 handle = bo->hw_res_handle;
454 } else {
455 handle = 0;
456 }
457
458 if (bo && bo->dumb && (plane->state->fb != old_state->fb)) {
459 /* new cursor -- update & wait */
460 struct virtio_gpu_object_array *objs;
461
462 objs = virtio_gpu_array_alloc(1);
463 if (!objs)
464 return;
465 virtio_gpu_array_add_obj(objs, vgfb->base.obj[0]);
466 if (virtio_gpu_lock_one_resv_uninterruptible(objs)) {
467 virtio_gpu_array_put_free(objs);
468 return;
469 }
470 virtio_gpu_cmd_transfer_to_host_2d
471 (vgdev, 0,
472 plane->state->crtc_w,
473 plane->state->crtc_h,
474 0, 0, objs, vgplane_st->fence);
475 virtio_gpu_notify(vgdev);
476 dma_fence_wait(&vgplane_st->fence->f, true);
477 }
478
479 if (plane->state->fb != old_state->fb) {
480 DRM_DEBUG("update, handle %d, pos +%d+%d, hot %d,%d\n", handle,
481 plane->state->crtc_x,
482 plane->state->crtc_y,
483 plane->state->hotspot_x,
484 plane->state->hotspot_y);
485 output->cursor.hdr.type =
486 cpu_to_le32(VIRTIO_GPU_CMD_UPDATE_CURSOR);
487 output->cursor.resource_id = cpu_to_le32(handle);
488 if (plane->state->fb) {
489 output->cursor.hot_x =
490 cpu_to_le32(plane->state->hotspot_x);
491 output->cursor.hot_y =
492 cpu_to_le32(plane->state->hotspot_y);
493 } else {
494 output->cursor.hot_x = cpu_to_le32(0);
495 output->cursor.hot_y = cpu_to_le32(0);
496 }
497 } else {
498 DRM_DEBUG("move +%d+%d\n",
499 plane->state->crtc_x,
500 plane->state->crtc_y);
501 output->cursor.hdr.type =
502 cpu_to_le32(VIRTIO_GPU_CMD_MOVE_CURSOR);
503 }
504 output->cursor.pos.x = cpu_to_le32(plane->state->crtc_x);
505 output->cursor.pos.y = cpu_to_le32(plane->state->crtc_y);
506 virtio_gpu_cursor_ping(vgdev, output);
507 }
508
virtio_drm_get_scanout_buffer(struct drm_plane * plane,struct drm_scanout_buffer * sb)509 static int virtio_drm_get_scanout_buffer(struct drm_plane *plane,
510 struct drm_scanout_buffer *sb)
511 {
512 struct virtio_gpu_object *bo;
513
514 if (!plane->state || !plane->state->fb || !plane->state->visible)
515 return -ENODEV;
516
517 bo = gem_to_virtio_gpu_obj(plane->state->fb->obj[0]);
518
519 if (virtio_gpu_is_vram(bo) || drm_gem_is_imported(&bo->base.base))
520 return -ENODEV;
521
522 if (bo->base.vaddr) {
523 iosys_map_set_vaddr(&sb->map[0], bo->base.vaddr);
524 } else {
525 struct drm_gem_shmem_object *shmem = &bo->base;
526
527 if (!shmem->pages)
528 return -ENODEV;
529 /* map scanout buffer later */
530 sb->pages = shmem->pages;
531 }
532
533 sb->format = plane->state->fb->format;
534 sb->height = plane->state->fb->height;
535 sb->width = plane->state->fb->width;
536 sb->pitch[0] = plane->state->fb->pitches[0];
537 return 0;
538 }
539
virtio_panic_flush(struct drm_plane * plane)540 static void virtio_panic_flush(struct drm_plane *plane)
541 {
542 struct virtio_gpu_object *bo;
543 struct drm_device *dev = plane->dev;
544 struct virtio_gpu_device *vgdev = dev->dev_private;
545 struct drm_rect rect;
546
547 rect.x1 = 0;
548 rect.y1 = 0;
549 rect.x2 = plane->state->fb->width;
550 rect.y2 = plane->state->fb->height;
551
552 bo = gem_to_virtio_gpu_obj(plane->state->fb->obj[0]);
553
554 if (bo->dumb) {
555 if (virtio_gpu_panic_update_dumb_bo(vgdev, plane->state,
556 &rect))
557 return;
558 }
559
560 virtio_gpu_panic_resource_flush(plane,
561 plane->state->src_x >> 16,
562 plane->state->src_y >> 16,
563 plane->state->src_w >> 16,
564 plane->state->src_h >> 16);
565 }
566
567 static const struct drm_plane_helper_funcs virtio_gpu_primary_helper_funcs = {
568 .prepare_fb = virtio_gpu_plane_prepare_fb,
569 .cleanup_fb = virtio_gpu_plane_cleanup_fb,
570 .atomic_check = virtio_gpu_plane_atomic_check,
571 .atomic_update = virtio_gpu_primary_plane_update,
572 .get_scanout_buffer = virtio_drm_get_scanout_buffer,
573 .panic_flush = virtio_panic_flush,
574 };
575
576 static const struct drm_plane_helper_funcs virtio_gpu_cursor_helper_funcs = {
577 .prepare_fb = virtio_gpu_plane_prepare_fb,
578 .cleanup_fb = virtio_gpu_plane_cleanup_fb,
579 .atomic_check = virtio_gpu_plane_atomic_check,
580 .atomic_update = virtio_gpu_cursor_plane_update,
581 };
582
virtio_gpu_plane_init(struct virtio_gpu_device * vgdev,enum drm_plane_type type,int index)583 struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev,
584 enum drm_plane_type type,
585 int index)
586 {
587 struct drm_device *dev = vgdev->ddev;
588 const struct drm_plane_helper_funcs *funcs;
589 struct drm_plane *plane;
590 const uint32_t *formats;
591 int nformats;
592
593 if (type == DRM_PLANE_TYPE_CURSOR) {
594 formats = virtio_gpu_cursor_formats;
595 nformats = ARRAY_SIZE(virtio_gpu_cursor_formats);
596 funcs = &virtio_gpu_cursor_helper_funcs;
597 } else {
598 formats = virtio_gpu_formats;
599 nformats = ARRAY_SIZE(virtio_gpu_formats);
600 funcs = &virtio_gpu_primary_helper_funcs;
601 }
602
603 plane = drmm_universal_plane_alloc(dev, struct drm_plane, dev,
604 1 << index, &virtio_gpu_plane_funcs,
605 formats, nformats, NULL, type, NULL);
606 if (IS_ERR(plane))
607 return plane;
608
609 drm_plane_helper_add(plane, funcs);
610
611 if (type == DRM_PLANE_TYPE_PRIMARY)
612 drm_plane_enable_fb_damage_clips(plane);
613 else if (type == DRM_PLANE_TYPE_CURSOR)
614 drm_plane_create_blend_mode_property(plane,
615 BIT(DRM_MODE_BLEND_PREMULTI));
616
617 return plane;
618 }
619