162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (C) 2015 Red Hat, Inc.
362306a36Sopenharmony_ci * All Rights Reserved.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining
662306a36Sopenharmony_ci * a copy of this software and associated documentation files (the
762306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
862306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
962306a36Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to
1062306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
1162306a36Sopenharmony_ci * the following conditions:
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the
1462306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial
1562306a36Sopenharmony_ci * portions of the Software.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1862306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1962306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
2062306a36Sopenharmony_ci * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
2162306a36Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
2262306a36Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2362306a36Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2462306a36Sopenharmony_ci */
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include <drm/drm_atomic_helper.h>
2762306a36Sopenharmony_ci#include <drm/drm_damage_helper.h>
2862306a36Sopenharmony_ci#include <drm/drm_fourcc.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include "virtgpu_drv.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic const uint32_t virtio_gpu_formats[] = {
3362306a36Sopenharmony_ci	DRM_FORMAT_HOST_XRGB8888,
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic const uint32_t virtio_gpu_cursor_formats[] = {
3762306a36Sopenharmony_ci	DRM_FORMAT_HOST_ARGB8888,
3862306a36Sopenharmony_ci};
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ciuint32_t virtio_gpu_translate_format(uint32_t drm_fourcc)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	uint32_t format;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	switch (drm_fourcc) {
4562306a36Sopenharmony_ci	case DRM_FORMAT_XRGB8888:
4662306a36Sopenharmony_ci		format = VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM;
4762306a36Sopenharmony_ci		break;
4862306a36Sopenharmony_ci	case DRM_FORMAT_ARGB8888:
4962306a36Sopenharmony_ci		format = VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM;
5062306a36Sopenharmony_ci		break;
5162306a36Sopenharmony_ci	case DRM_FORMAT_BGRX8888:
5262306a36Sopenharmony_ci		format = VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM;
5362306a36Sopenharmony_ci		break;
5462306a36Sopenharmony_ci	case DRM_FORMAT_BGRA8888:
5562306a36Sopenharmony_ci		format = VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM;
5662306a36Sopenharmony_ci		break;
5762306a36Sopenharmony_ci	default:
5862306a36Sopenharmony_ci		/*
5962306a36Sopenharmony_ci		 * This should not happen, we handle everything listed
6062306a36Sopenharmony_ci		 * in virtio_gpu_formats[].
6162306a36Sopenharmony_ci		 */
6262306a36Sopenharmony_ci		format = 0;
6362306a36Sopenharmony_ci		break;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci	WARN_ON(format == 0);
6662306a36Sopenharmony_ci	return format;
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic const struct drm_plane_funcs virtio_gpu_plane_funcs = {
7062306a36Sopenharmony_ci	.update_plane		= drm_atomic_helper_update_plane,
7162306a36Sopenharmony_ci	.disable_plane		= drm_atomic_helper_disable_plane,
7262306a36Sopenharmony_ci	.reset			= drm_atomic_helper_plane_reset,
7362306a36Sopenharmony_ci	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
7462306a36Sopenharmony_ci	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic int virtio_gpu_plane_atomic_check(struct drm_plane *plane,
7862306a36Sopenharmony_ci					 struct drm_atomic_state *state)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
8162306a36Sopenharmony_ci										 plane);
8262306a36Sopenharmony_ci	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state,
8362306a36Sopenharmony_ci										 plane);
8462306a36Sopenharmony_ci	bool is_cursor = plane->type == DRM_PLANE_TYPE_CURSOR;
8562306a36Sopenharmony_ci	struct drm_crtc_state *crtc_state;
8662306a36Sopenharmony_ci	int ret;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc))
8962306a36Sopenharmony_ci		return 0;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	/*
9262306a36Sopenharmony_ci	 * Ignore damage clips if the framebuffer attached to the plane's state
9362306a36Sopenharmony_ci	 * has changed since the last plane update (page-flip). In this case, a
9462306a36Sopenharmony_ci	 * full plane update should happen because uploads are done per-buffer.
9562306a36Sopenharmony_ci	 */
9662306a36Sopenharmony_ci	if (old_plane_state->fb != new_plane_state->fb)
9762306a36Sopenharmony_ci		new_plane_state->ignore_damage_clips = true;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	crtc_state = drm_atomic_get_crtc_state(state,
10062306a36Sopenharmony_ci					       new_plane_state->crtc);
10162306a36Sopenharmony_ci	if (IS_ERR(crtc_state))
10262306a36Sopenharmony_ci                return PTR_ERR(crtc_state);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
10562306a36Sopenharmony_ci						  DRM_PLANE_NO_SCALING,
10662306a36Sopenharmony_ci						  DRM_PLANE_NO_SCALING,
10762306a36Sopenharmony_ci						  is_cursor, true);
10862306a36Sopenharmony_ci	return ret;
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic void virtio_gpu_update_dumb_bo(struct virtio_gpu_device *vgdev,
11262306a36Sopenharmony_ci				      struct drm_plane_state *state,
11362306a36Sopenharmony_ci				      struct drm_rect *rect)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	struct virtio_gpu_object *bo =
11662306a36Sopenharmony_ci		gem_to_virtio_gpu_obj(state->fb->obj[0]);
11762306a36Sopenharmony_ci	struct virtio_gpu_object_array *objs;
11862306a36Sopenharmony_ci	uint32_t w = rect->x2 - rect->x1;
11962306a36Sopenharmony_ci	uint32_t h = rect->y2 - rect->y1;
12062306a36Sopenharmony_ci	uint32_t x = rect->x1;
12162306a36Sopenharmony_ci	uint32_t y = rect->y1;
12262306a36Sopenharmony_ci	uint32_t off = x * state->fb->format->cpp[0] +
12362306a36Sopenharmony_ci		y * state->fb->pitches[0];
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	objs = virtio_gpu_array_alloc(1);
12662306a36Sopenharmony_ci	if (!objs)
12762306a36Sopenharmony_ci		return;
12862306a36Sopenharmony_ci	virtio_gpu_array_add_obj(objs, &bo->base.base);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	virtio_gpu_cmd_transfer_to_host_2d(vgdev, off, w, h, x, y,
13162306a36Sopenharmony_ci					   objs, NULL);
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic void virtio_gpu_resource_flush(struct drm_plane *plane,
13562306a36Sopenharmony_ci				      uint32_t x, uint32_t y,
13662306a36Sopenharmony_ci				      uint32_t width, uint32_t height)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	struct drm_device *dev = plane->dev;
13962306a36Sopenharmony_ci	struct virtio_gpu_device *vgdev = dev->dev_private;
14062306a36Sopenharmony_ci	struct virtio_gpu_framebuffer *vgfb;
14162306a36Sopenharmony_ci	struct virtio_gpu_object *bo;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	vgfb = to_virtio_gpu_framebuffer(plane->state->fb);
14462306a36Sopenharmony_ci	bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
14562306a36Sopenharmony_ci	if (vgfb->fence) {
14662306a36Sopenharmony_ci		struct virtio_gpu_object_array *objs;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci		objs = virtio_gpu_array_alloc(1);
14962306a36Sopenharmony_ci		if (!objs)
15062306a36Sopenharmony_ci			return;
15162306a36Sopenharmony_ci		virtio_gpu_array_add_obj(objs, vgfb->base.obj[0]);
15262306a36Sopenharmony_ci		virtio_gpu_array_lock_resv(objs);
15362306a36Sopenharmony_ci		virtio_gpu_cmd_resource_flush(vgdev, bo->hw_res_handle, x, y,
15462306a36Sopenharmony_ci					      width, height, objs, vgfb->fence);
15562306a36Sopenharmony_ci		virtio_gpu_notify(vgdev);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci		dma_fence_wait_timeout(&vgfb->fence->f, true,
15862306a36Sopenharmony_ci				       msecs_to_jiffies(50));
15962306a36Sopenharmony_ci		dma_fence_put(&vgfb->fence->f);
16062306a36Sopenharmony_ci		vgfb->fence = NULL;
16162306a36Sopenharmony_ci	} else {
16262306a36Sopenharmony_ci		virtio_gpu_cmd_resource_flush(vgdev, bo->hw_res_handle, x, y,
16362306a36Sopenharmony_ci					      width, height, NULL, NULL);
16462306a36Sopenharmony_ci		virtio_gpu_notify(vgdev);
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic void virtio_gpu_primary_plane_update(struct drm_plane *plane,
16962306a36Sopenharmony_ci					    struct drm_atomic_state *state)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
17262306a36Sopenharmony_ci									   plane);
17362306a36Sopenharmony_ci	struct drm_device *dev = plane->dev;
17462306a36Sopenharmony_ci	struct virtio_gpu_device *vgdev = dev->dev_private;
17562306a36Sopenharmony_ci	struct virtio_gpu_output *output = NULL;
17662306a36Sopenharmony_ci	struct virtio_gpu_object *bo;
17762306a36Sopenharmony_ci	struct drm_rect rect;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	if (plane->state->crtc)
18062306a36Sopenharmony_ci		output = drm_crtc_to_virtio_gpu_output(plane->state->crtc);
18162306a36Sopenharmony_ci	if (old_state->crtc)
18262306a36Sopenharmony_ci		output = drm_crtc_to_virtio_gpu_output(old_state->crtc);
18362306a36Sopenharmony_ci	if (WARN_ON(!output))
18462306a36Sopenharmony_ci		return;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (!plane->state->fb || !output->crtc.state->active) {
18762306a36Sopenharmony_ci		DRM_DEBUG("nofb\n");
18862306a36Sopenharmony_ci		virtio_gpu_cmd_set_scanout(vgdev, output->index, 0,
18962306a36Sopenharmony_ci					   plane->state->src_w >> 16,
19062306a36Sopenharmony_ci					   plane->state->src_h >> 16,
19162306a36Sopenharmony_ci					   0, 0);
19262306a36Sopenharmony_ci		virtio_gpu_notify(vgdev);
19362306a36Sopenharmony_ci		return;
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (!drm_atomic_helper_damage_merged(old_state, plane->state, &rect))
19762306a36Sopenharmony_ci		return;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	bo = gem_to_virtio_gpu_obj(plane->state->fb->obj[0]);
20062306a36Sopenharmony_ci	if (bo->dumb)
20162306a36Sopenharmony_ci		virtio_gpu_update_dumb_bo(vgdev, plane->state, &rect);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	if (plane->state->fb != old_state->fb ||
20462306a36Sopenharmony_ci	    plane->state->src_w != old_state->src_w ||
20562306a36Sopenharmony_ci	    plane->state->src_h != old_state->src_h ||
20662306a36Sopenharmony_ci	    plane->state->src_x != old_state->src_x ||
20762306a36Sopenharmony_ci	    plane->state->src_y != old_state->src_y ||
20862306a36Sopenharmony_ci	    output->needs_modeset) {
20962306a36Sopenharmony_ci		output->needs_modeset = false;
21062306a36Sopenharmony_ci		DRM_DEBUG("handle 0x%x, crtc %dx%d+%d+%d, src %dx%d+%d+%d\n",
21162306a36Sopenharmony_ci			  bo->hw_res_handle,
21262306a36Sopenharmony_ci			  plane->state->crtc_w, plane->state->crtc_h,
21362306a36Sopenharmony_ci			  plane->state->crtc_x, plane->state->crtc_y,
21462306a36Sopenharmony_ci			  plane->state->src_w >> 16,
21562306a36Sopenharmony_ci			  plane->state->src_h >> 16,
21662306a36Sopenharmony_ci			  plane->state->src_x >> 16,
21762306a36Sopenharmony_ci			  plane->state->src_y >> 16);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci		if (bo->host3d_blob || bo->guest_blob) {
22062306a36Sopenharmony_ci			virtio_gpu_cmd_set_scanout_blob
22162306a36Sopenharmony_ci						(vgdev, output->index, bo,
22262306a36Sopenharmony_ci						 plane->state->fb,
22362306a36Sopenharmony_ci						 plane->state->src_w >> 16,
22462306a36Sopenharmony_ci						 plane->state->src_h >> 16,
22562306a36Sopenharmony_ci						 plane->state->src_x >> 16,
22662306a36Sopenharmony_ci						 plane->state->src_y >> 16);
22762306a36Sopenharmony_ci		} else {
22862306a36Sopenharmony_ci			virtio_gpu_cmd_set_scanout(vgdev, output->index,
22962306a36Sopenharmony_ci						   bo->hw_res_handle,
23062306a36Sopenharmony_ci						   plane->state->src_w >> 16,
23162306a36Sopenharmony_ci						   plane->state->src_h >> 16,
23262306a36Sopenharmony_ci						   plane->state->src_x >> 16,
23362306a36Sopenharmony_ci						   plane->state->src_y >> 16);
23462306a36Sopenharmony_ci		}
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	virtio_gpu_resource_flush(plane,
23862306a36Sopenharmony_ci				  rect.x1,
23962306a36Sopenharmony_ci				  rect.y1,
24062306a36Sopenharmony_ci				  rect.x2 - rect.x1,
24162306a36Sopenharmony_ci				  rect.y2 - rect.y1);
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic int virtio_gpu_plane_prepare_fb(struct drm_plane *plane,
24562306a36Sopenharmony_ci				       struct drm_plane_state *new_state)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	struct drm_device *dev = plane->dev;
24862306a36Sopenharmony_ci	struct virtio_gpu_device *vgdev = dev->dev_private;
24962306a36Sopenharmony_ci	struct virtio_gpu_framebuffer *vgfb;
25062306a36Sopenharmony_ci	struct virtio_gpu_object *bo;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	if (!new_state->fb)
25362306a36Sopenharmony_ci		return 0;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	vgfb = to_virtio_gpu_framebuffer(new_state->fb);
25662306a36Sopenharmony_ci	bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
25762306a36Sopenharmony_ci	if (!bo || (plane->type == DRM_PLANE_TYPE_PRIMARY && !bo->guest_blob))
25862306a36Sopenharmony_ci		return 0;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	if (bo->dumb && (plane->state->fb != new_state->fb)) {
26162306a36Sopenharmony_ci		vgfb->fence = virtio_gpu_fence_alloc(vgdev, vgdev->fence_drv.context,
26262306a36Sopenharmony_ci						     0);
26362306a36Sopenharmony_ci		if (!vgfb->fence)
26462306a36Sopenharmony_ci			return -ENOMEM;
26562306a36Sopenharmony_ci	}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	return 0;
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic void virtio_gpu_plane_cleanup_fb(struct drm_plane *plane,
27162306a36Sopenharmony_ci					struct drm_plane_state *state)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	struct virtio_gpu_framebuffer *vgfb;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	if (!state->fb)
27662306a36Sopenharmony_ci		return;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	vgfb = to_virtio_gpu_framebuffer(state->fb);
27962306a36Sopenharmony_ci	if (vgfb->fence) {
28062306a36Sopenharmony_ci		dma_fence_put(&vgfb->fence->f);
28162306a36Sopenharmony_ci		vgfb->fence = NULL;
28262306a36Sopenharmony_ci	}
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic void virtio_gpu_cursor_plane_update(struct drm_plane *plane,
28662306a36Sopenharmony_ci					   struct drm_atomic_state *state)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
28962306a36Sopenharmony_ci									   plane);
29062306a36Sopenharmony_ci	struct drm_device *dev = plane->dev;
29162306a36Sopenharmony_ci	struct virtio_gpu_device *vgdev = dev->dev_private;
29262306a36Sopenharmony_ci	struct virtio_gpu_output *output = NULL;
29362306a36Sopenharmony_ci	struct virtio_gpu_framebuffer *vgfb;
29462306a36Sopenharmony_ci	struct virtio_gpu_object *bo = NULL;
29562306a36Sopenharmony_ci	uint32_t handle;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	if (plane->state->crtc)
29862306a36Sopenharmony_ci		output = drm_crtc_to_virtio_gpu_output(plane->state->crtc);
29962306a36Sopenharmony_ci	if (old_state->crtc)
30062306a36Sopenharmony_ci		output = drm_crtc_to_virtio_gpu_output(old_state->crtc);
30162306a36Sopenharmony_ci	if (WARN_ON(!output))
30262306a36Sopenharmony_ci		return;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (plane->state->fb) {
30562306a36Sopenharmony_ci		vgfb = to_virtio_gpu_framebuffer(plane->state->fb);
30662306a36Sopenharmony_ci		bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
30762306a36Sopenharmony_ci		handle = bo->hw_res_handle;
30862306a36Sopenharmony_ci	} else {
30962306a36Sopenharmony_ci		handle = 0;
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	if (bo && bo->dumb && (plane->state->fb != old_state->fb)) {
31362306a36Sopenharmony_ci		/* new cursor -- update & wait */
31462306a36Sopenharmony_ci		struct virtio_gpu_object_array *objs;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci		objs = virtio_gpu_array_alloc(1);
31762306a36Sopenharmony_ci		if (!objs)
31862306a36Sopenharmony_ci			return;
31962306a36Sopenharmony_ci		virtio_gpu_array_add_obj(objs, vgfb->base.obj[0]);
32062306a36Sopenharmony_ci		virtio_gpu_array_lock_resv(objs);
32162306a36Sopenharmony_ci		virtio_gpu_cmd_transfer_to_host_2d
32262306a36Sopenharmony_ci			(vgdev, 0,
32362306a36Sopenharmony_ci			 plane->state->crtc_w,
32462306a36Sopenharmony_ci			 plane->state->crtc_h,
32562306a36Sopenharmony_ci			 0, 0, objs, vgfb->fence);
32662306a36Sopenharmony_ci		virtio_gpu_notify(vgdev);
32762306a36Sopenharmony_ci		dma_fence_wait(&vgfb->fence->f, true);
32862306a36Sopenharmony_ci		dma_fence_put(&vgfb->fence->f);
32962306a36Sopenharmony_ci		vgfb->fence = NULL;
33062306a36Sopenharmony_ci	}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (plane->state->fb != old_state->fb) {
33362306a36Sopenharmony_ci		DRM_DEBUG("update, handle %d, pos +%d+%d, hot %d,%d\n", handle,
33462306a36Sopenharmony_ci			  plane->state->crtc_x,
33562306a36Sopenharmony_ci			  plane->state->crtc_y,
33662306a36Sopenharmony_ci			  plane->state->fb ? plane->state->fb->hot_x : 0,
33762306a36Sopenharmony_ci			  plane->state->fb ? plane->state->fb->hot_y : 0);
33862306a36Sopenharmony_ci		output->cursor.hdr.type =
33962306a36Sopenharmony_ci			cpu_to_le32(VIRTIO_GPU_CMD_UPDATE_CURSOR);
34062306a36Sopenharmony_ci		output->cursor.resource_id = cpu_to_le32(handle);
34162306a36Sopenharmony_ci		if (plane->state->fb) {
34262306a36Sopenharmony_ci			output->cursor.hot_x =
34362306a36Sopenharmony_ci				cpu_to_le32(plane->state->fb->hot_x);
34462306a36Sopenharmony_ci			output->cursor.hot_y =
34562306a36Sopenharmony_ci				cpu_to_le32(plane->state->fb->hot_y);
34662306a36Sopenharmony_ci		} else {
34762306a36Sopenharmony_ci			output->cursor.hot_x = cpu_to_le32(0);
34862306a36Sopenharmony_ci			output->cursor.hot_y = cpu_to_le32(0);
34962306a36Sopenharmony_ci		}
35062306a36Sopenharmony_ci	} else {
35162306a36Sopenharmony_ci		DRM_DEBUG("move +%d+%d\n",
35262306a36Sopenharmony_ci			  plane->state->crtc_x,
35362306a36Sopenharmony_ci			  plane->state->crtc_y);
35462306a36Sopenharmony_ci		output->cursor.hdr.type =
35562306a36Sopenharmony_ci			cpu_to_le32(VIRTIO_GPU_CMD_MOVE_CURSOR);
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci	output->cursor.pos.x = cpu_to_le32(plane->state->crtc_x);
35862306a36Sopenharmony_ci	output->cursor.pos.y = cpu_to_le32(plane->state->crtc_y);
35962306a36Sopenharmony_ci	virtio_gpu_cursor_ping(vgdev, output);
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_cistatic const struct drm_plane_helper_funcs virtio_gpu_primary_helper_funcs = {
36362306a36Sopenharmony_ci	.prepare_fb		= virtio_gpu_plane_prepare_fb,
36462306a36Sopenharmony_ci	.cleanup_fb		= virtio_gpu_plane_cleanup_fb,
36562306a36Sopenharmony_ci	.atomic_check		= virtio_gpu_plane_atomic_check,
36662306a36Sopenharmony_ci	.atomic_update		= virtio_gpu_primary_plane_update,
36762306a36Sopenharmony_ci};
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_cistatic const struct drm_plane_helper_funcs virtio_gpu_cursor_helper_funcs = {
37062306a36Sopenharmony_ci	.prepare_fb		= virtio_gpu_plane_prepare_fb,
37162306a36Sopenharmony_ci	.cleanup_fb		= virtio_gpu_plane_cleanup_fb,
37262306a36Sopenharmony_ci	.atomic_check		= virtio_gpu_plane_atomic_check,
37362306a36Sopenharmony_ci	.atomic_update		= virtio_gpu_cursor_plane_update,
37462306a36Sopenharmony_ci};
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_cistruct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev,
37762306a36Sopenharmony_ci					enum drm_plane_type type,
37862306a36Sopenharmony_ci					int index)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci	struct drm_device *dev = vgdev->ddev;
38162306a36Sopenharmony_ci	const struct drm_plane_helper_funcs *funcs;
38262306a36Sopenharmony_ci	struct drm_plane *plane;
38362306a36Sopenharmony_ci	const uint32_t *formats;
38462306a36Sopenharmony_ci	int nformats;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	if (type == DRM_PLANE_TYPE_CURSOR) {
38762306a36Sopenharmony_ci		formats = virtio_gpu_cursor_formats;
38862306a36Sopenharmony_ci		nformats = ARRAY_SIZE(virtio_gpu_cursor_formats);
38962306a36Sopenharmony_ci		funcs = &virtio_gpu_cursor_helper_funcs;
39062306a36Sopenharmony_ci	} else {
39162306a36Sopenharmony_ci		formats = virtio_gpu_formats;
39262306a36Sopenharmony_ci		nformats = ARRAY_SIZE(virtio_gpu_formats);
39362306a36Sopenharmony_ci		funcs = &virtio_gpu_primary_helper_funcs;
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	plane = drmm_universal_plane_alloc(dev, struct drm_plane, dev,
39762306a36Sopenharmony_ci					   1 << index, &virtio_gpu_plane_funcs,
39862306a36Sopenharmony_ci					   formats, nformats, NULL, type, NULL);
39962306a36Sopenharmony_ci	if (IS_ERR(plane))
40062306a36Sopenharmony_ci		return plane;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	drm_plane_helper_add(plane, funcs);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	if (type == DRM_PLANE_TYPE_PRIMARY)
40562306a36Sopenharmony_ci		drm_plane_enable_fb_damage_clips(plane);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	return plane;
40862306a36Sopenharmony_ci}
409