1dc5698e8SDave Airlie /*
2dc5698e8SDave Airlie  * Copyright (C) 2015 Red Hat, Inc.
3dc5698e8SDave Airlie  * All Rights Reserved.
4dc5698e8SDave Airlie  *
5dc5698e8SDave Airlie  * Permission is hereby granted, free of charge, to any person obtaining
6dc5698e8SDave Airlie  * a copy of this software and associated documentation files (the
7dc5698e8SDave Airlie  * "Software"), to deal in the Software without restriction, including
8dc5698e8SDave Airlie  * without limitation the rights to use, copy, modify, merge, publish,
9dc5698e8SDave Airlie  * distribute, sublicense, and/or sell copies of the Software, and to
10dc5698e8SDave Airlie  * permit persons to whom the Software is furnished to do so, subject to
11dc5698e8SDave Airlie  * the following conditions:
12dc5698e8SDave Airlie  *
13dc5698e8SDave Airlie  * The above copyright notice and this permission notice (including the
14dc5698e8SDave Airlie  * next paragraph) shall be included in all copies or substantial
15dc5698e8SDave Airlie  * portions of the Software.
16dc5698e8SDave Airlie  *
17dc5698e8SDave Airlie  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18dc5698e8SDave Airlie  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19dc5698e8SDave Airlie  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20dc5698e8SDave Airlie  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21dc5698e8SDave Airlie  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22dc5698e8SDave Airlie  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23dc5698e8SDave Airlie  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24dc5698e8SDave Airlie  */
25dc5698e8SDave Airlie 
26dc5698e8SDave Airlie #include "virtgpu_drv.h"
27dc5698e8SDave Airlie #include <drm/drm_plane_helper.h>
28dc5698e8SDave Airlie #include <drm/drm_atomic_helper.h>
29dc5698e8SDave Airlie 
30dc5698e8SDave Airlie static const uint32_t virtio_gpu_formats[] = {
31dc5698e8SDave Airlie 	DRM_FORMAT_XRGB8888,
32dc5698e8SDave Airlie 	DRM_FORMAT_ARGB8888,
33dc5698e8SDave Airlie 	DRM_FORMAT_BGRX8888,
34dc5698e8SDave Airlie 	DRM_FORMAT_BGRA8888,
35dc5698e8SDave Airlie 	DRM_FORMAT_RGBX8888,
36dc5698e8SDave Airlie 	DRM_FORMAT_RGBA8888,
37dc5698e8SDave Airlie 	DRM_FORMAT_XBGR8888,
38dc5698e8SDave Airlie 	DRM_FORMAT_ABGR8888,
39dc5698e8SDave Airlie };
40dc5698e8SDave Airlie 
41bbbed888SGerd Hoffmann static const uint32_t virtio_gpu_cursor_formats[] = {
4299748ab6SLaurent Vivier #ifdef __BIG_ENDIAN
4399748ab6SLaurent Vivier 	DRM_FORMAT_BGRA8888,
4499748ab6SLaurent Vivier #else
45bbbed888SGerd Hoffmann 	DRM_FORMAT_ARGB8888,
4699748ab6SLaurent Vivier #endif
47bbbed888SGerd Hoffmann };
48bbbed888SGerd Hoffmann 
49d519cb76SGerd Hoffmann uint32_t virtio_gpu_translate_format(uint32_t drm_fourcc)
50d519cb76SGerd Hoffmann {
51d519cb76SGerd Hoffmann 	uint32_t format;
52d519cb76SGerd Hoffmann 
53d519cb76SGerd Hoffmann 	switch (drm_fourcc) {
54d519cb76SGerd Hoffmann #ifdef __BIG_ENDIAN
55d519cb76SGerd Hoffmann 	case DRM_FORMAT_XRGB8888:
56d519cb76SGerd Hoffmann 		format = VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM;
57d519cb76SGerd Hoffmann 		break;
58d519cb76SGerd Hoffmann 	case DRM_FORMAT_ARGB8888:
59d519cb76SGerd Hoffmann 		format = VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM;
60d519cb76SGerd Hoffmann 		break;
61d519cb76SGerd Hoffmann 	case DRM_FORMAT_BGRX8888:
62d519cb76SGerd Hoffmann 		format = VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM;
63d519cb76SGerd Hoffmann 		break;
64d519cb76SGerd Hoffmann 	case DRM_FORMAT_BGRA8888:
65d519cb76SGerd Hoffmann 		format = VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM;
66d519cb76SGerd Hoffmann 		break;
67d519cb76SGerd Hoffmann 	case DRM_FORMAT_RGBX8888:
68d519cb76SGerd Hoffmann 		format = VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM;
69d519cb76SGerd Hoffmann 		break;
70d519cb76SGerd Hoffmann 	case DRM_FORMAT_RGBA8888:
71d519cb76SGerd Hoffmann 		format = VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM;
72d519cb76SGerd Hoffmann 		break;
73d519cb76SGerd Hoffmann 	case DRM_FORMAT_XBGR8888:
74d519cb76SGerd Hoffmann 		format = VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM;
75d519cb76SGerd Hoffmann 		break;
76d519cb76SGerd Hoffmann 	case DRM_FORMAT_ABGR8888:
77d519cb76SGerd Hoffmann 		format = VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM;
78d519cb76SGerd Hoffmann 		break;
79d519cb76SGerd Hoffmann #else
80d519cb76SGerd Hoffmann 	case DRM_FORMAT_XRGB8888:
81d519cb76SGerd Hoffmann 		format = VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM;
82d519cb76SGerd Hoffmann 		break;
83d519cb76SGerd Hoffmann 	case DRM_FORMAT_ARGB8888:
84d519cb76SGerd Hoffmann 		format = VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM;
85d519cb76SGerd Hoffmann 		break;
86d519cb76SGerd Hoffmann 	case DRM_FORMAT_BGRX8888:
87d519cb76SGerd Hoffmann 		format = VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM;
88d519cb76SGerd Hoffmann 		break;
89d519cb76SGerd Hoffmann 	case DRM_FORMAT_BGRA8888:
90d519cb76SGerd Hoffmann 		format = VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM;
91d519cb76SGerd Hoffmann 		break;
92d519cb76SGerd Hoffmann 	case DRM_FORMAT_RGBX8888:
93d519cb76SGerd Hoffmann 		format = VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM;
94d519cb76SGerd Hoffmann 		break;
95d519cb76SGerd Hoffmann 	case DRM_FORMAT_RGBA8888:
96d519cb76SGerd Hoffmann 		format = VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM;
97d519cb76SGerd Hoffmann 		break;
98d519cb76SGerd Hoffmann 	case DRM_FORMAT_XBGR8888:
99d519cb76SGerd Hoffmann 		format = VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM;
100d519cb76SGerd Hoffmann 		break;
101d519cb76SGerd Hoffmann 	case DRM_FORMAT_ABGR8888:
102d519cb76SGerd Hoffmann 		format = VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM;
103d519cb76SGerd Hoffmann 		break;
104d519cb76SGerd Hoffmann #endif
105d519cb76SGerd Hoffmann 	default:
106d519cb76SGerd Hoffmann 		/*
107d519cb76SGerd Hoffmann 		 * This should not happen, we handle everything listed
108d519cb76SGerd Hoffmann 		 * in virtio_gpu_formats[].
109d519cb76SGerd Hoffmann 		 */
110d519cb76SGerd Hoffmann 		format = 0;
111d519cb76SGerd Hoffmann 		break;
112d519cb76SGerd Hoffmann 	}
113d519cb76SGerd Hoffmann 	WARN_ON(format == 0);
114d519cb76SGerd Hoffmann 	return format;
115d519cb76SGerd Hoffmann }
116d519cb76SGerd Hoffmann 
117dc5698e8SDave Airlie static void virtio_gpu_plane_destroy(struct drm_plane *plane)
118dc5698e8SDave Airlie {
119fb70046cSGustavo Padovan 	drm_plane_cleanup(plane);
120dc5698e8SDave Airlie 	kfree(plane);
121dc5698e8SDave Airlie }
122dc5698e8SDave Airlie 
123dc5698e8SDave Airlie static const struct drm_plane_funcs virtio_gpu_plane_funcs = {
124dc5698e8SDave Airlie 	.update_plane		= drm_atomic_helper_update_plane,
125dc5698e8SDave Airlie 	.disable_plane		= drm_atomic_helper_disable_plane,
126dc5698e8SDave Airlie 	.destroy		= virtio_gpu_plane_destroy,
127dc5698e8SDave Airlie 	.reset			= drm_atomic_helper_plane_reset,
128dc5698e8SDave Airlie 	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
129dc5698e8SDave Airlie 	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
130dc5698e8SDave Airlie };
131dc5698e8SDave Airlie 
132dc5698e8SDave Airlie static int virtio_gpu_plane_atomic_check(struct drm_plane *plane,
133dc5698e8SDave Airlie 					 struct drm_plane_state *state)
134dc5698e8SDave Airlie {
135dc5698e8SDave Airlie 	return 0;
136dc5698e8SDave Airlie }
137dc5698e8SDave Airlie 
138bbbed888SGerd Hoffmann static void virtio_gpu_primary_plane_update(struct drm_plane *plane,
139dc5698e8SDave Airlie 					    struct drm_plane_state *old_state)
140dc5698e8SDave Airlie {
141dc5698e8SDave Airlie 	struct drm_device *dev = plane->dev;
142dc5698e8SDave Airlie 	struct virtio_gpu_device *vgdev = dev->dev_private;
143d3767d49SGerd Hoffmann 	struct virtio_gpu_output *output = NULL;
144dc5698e8SDave Airlie 	struct virtio_gpu_framebuffer *vgfb;
145dc5698e8SDave Airlie 	struct virtio_gpu_object *bo;
146dc5698e8SDave Airlie 	uint32_t handle;
147dc5698e8SDave Airlie 
148d3767d49SGerd Hoffmann 	if (plane->state->crtc)
149d3767d49SGerd Hoffmann 		output = drm_crtc_to_virtio_gpu_output(plane->state->crtc);
150d3767d49SGerd Hoffmann 	if (old_state->crtc)
151d3767d49SGerd Hoffmann 		output = drm_crtc_to_virtio_gpu_output(old_state->crtc);
152b28c69ddSHeinrich Schuchardt 	if (WARN_ON(!output))
153b28c69ddSHeinrich Schuchardt 		return;
154d3767d49SGerd Hoffmann 
15511c94aceSRob Herring 	if (plane->state->fb) {
15611c94aceSRob Herring 		vgfb = to_virtio_gpu_framebuffer(plane->state->fb);
157dc5698e8SDave Airlie 		bo = gem_to_virtio_gpu_obj(vgfb->obj);
158dc5698e8SDave Airlie 		handle = bo->hw_res_handle;
1594109e7f7SRob Herring 		if (bo->dumb) {
1604109e7f7SRob Herring 			virtio_gpu_cmd_transfer_to_host_2d
1614109e7f7SRob Herring 				(vgdev, handle, 0,
1620062795eSGerd Hoffmann 				 cpu_to_le32(plane->state->src_w >> 16),
1630062795eSGerd Hoffmann 				 cpu_to_le32(plane->state->src_h >> 16),
1648854a56fSMichael S. Tsirkin 				 cpu_to_le32(plane->state->src_x >> 16),
1658854a56fSMichael S. Tsirkin 				 cpu_to_le32(plane->state->src_y >> 16), NULL);
1664109e7f7SRob Herring 		}
167dc5698e8SDave Airlie 	} else {
168dc5698e8SDave Airlie 		handle = 0;
169dc5698e8SDave Airlie 	}
170dc5698e8SDave Airlie 
1710062795eSGerd Hoffmann 	DRM_DEBUG("handle 0x%x, crtc %dx%d+%d+%d, src %dx%d+%d+%d\n", handle,
172dc5698e8SDave Airlie 		  plane->state->crtc_w, plane->state->crtc_h,
1730062795eSGerd Hoffmann 		  plane->state->crtc_x, plane->state->crtc_y,
1740062795eSGerd Hoffmann 		  plane->state->src_w >> 16,
1750062795eSGerd Hoffmann 		  plane->state->src_h >> 16,
1760062795eSGerd Hoffmann 		  plane->state->src_x >> 16,
1770062795eSGerd Hoffmann 		  plane->state->src_y >> 16);
178dc5698e8SDave Airlie 	virtio_gpu_cmd_set_scanout(vgdev, output->index, handle,
1790062795eSGerd Hoffmann 				   plane->state->src_w >> 16,
1800062795eSGerd Hoffmann 				   plane->state->src_h >> 16,
1810062795eSGerd Hoffmann 				   plane->state->src_x >> 16,
1820062795eSGerd Hoffmann 				   plane->state->src_y >> 16);
183bd17d1c7SRob Herring 	virtio_gpu_cmd_resource_flush(vgdev, handle,
1840062795eSGerd Hoffmann 				      plane->state->src_x >> 16,
1850062795eSGerd Hoffmann 				      plane->state->src_y >> 16,
1860062795eSGerd Hoffmann 				      plane->state->src_w >> 16,
1870062795eSGerd Hoffmann 				      plane->state->src_h >> 16);
188dc5698e8SDave Airlie }
189dc5698e8SDave Airlie 
190bbbed888SGerd Hoffmann static void virtio_gpu_cursor_plane_update(struct drm_plane *plane,
191bbbed888SGerd Hoffmann 					   struct drm_plane_state *old_state)
192bbbed888SGerd Hoffmann {
193bbbed888SGerd Hoffmann 	struct drm_device *dev = plane->dev;
194bbbed888SGerd Hoffmann 	struct virtio_gpu_device *vgdev = dev->dev_private;
195bbbed888SGerd Hoffmann 	struct virtio_gpu_output *output = NULL;
196bbbed888SGerd Hoffmann 	struct virtio_gpu_framebuffer *vgfb;
197bbbed888SGerd Hoffmann 	struct virtio_gpu_fence *fence = NULL;
198bbbed888SGerd Hoffmann 	struct virtio_gpu_object *bo = NULL;
199bbbed888SGerd Hoffmann 	uint32_t handle;
200bbbed888SGerd Hoffmann 	int ret = 0;
201dc5698e8SDave Airlie 
202bbbed888SGerd Hoffmann 	if (plane->state->crtc)
203bbbed888SGerd Hoffmann 		output = drm_crtc_to_virtio_gpu_output(plane->state->crtc);
204bbbed888SGerd Hoffmann 	if (old_state->crtc)
205bbbed888SGerd Hoffmann 		output = drm_crtc_to_virtio_gpu_output(old_state->crtc);
206b28c69ddSHeinrich Schuchardt 	if (WARN_ON(!output))
207b28c69ddSHeinrich Schuchardt 		return;
208bbbed888SGerd Hoffmann 
209bbbed888SGerd Hoffmann 	if (plane->state->fb) {
210bbbed888SGerd Hoffmann 		vgfb = to_virtio_gpu_framebuffer(plane->state->fb);
211bbbed888SGerd Hoffmann 		bo = gem_to_virtio_gpu_obj(vgfb->obj);
212bbbed888SGerd Hoffmann 		handle = bo->hw_res_handle;
213bbbed888SGerd Hoffmann 	} else {
214bbbed888SGerd Hoffmann 		handle = 0;
215bbbed888SGerd Hoffmann 	}
216bbbed888SGerd Hoffmann 
217bbbed888SGerd Hoffmann 	if (bo && bo->dumb && (plane->state->fb != old_state->fb)) {
218bbbed888SGerd Hoffmann 		/* new cursor -- update & wait */
219bbbed888SGerd Hoffmann 		virtio_gpu_cmd_transfer_to_host_2d
220bbbed888SGerd Hoffmann 			(vgdev, handle, 0,
221bbbed888SGerd Hoffmann 			 cpu_to_le32(plane->state->crtc_w),
222bbbed888SGerd Hoffmann 			 cpu_to_le32(plane->state->crtc_h),
223bbbed888SGerd Hoffmann 			 0, 0, &fence);
224bbbed888SGerd Hoffmann 		ret = virtio_gpu_object_reserve(bo, false);
225bbbed888SGerd Hoffmann 		if (!ret) {
226bbbed888SGerd Hoffmann 			reservation_object_add_excl_fence(bo->tbo.resv,
227bbbed888SGerd Hoffmann 							  &fence->f);
228f54d1867SChris Wilson 			dma_fence_put(&fence->f);
229bbbed888SGerd Hoffmann 			fence = NULL;
230bbbed888SGerd Hoffmann 			virtio_gpu_object_unreserve(bo);
231bbbed888SGerd Hoffmann 			virtio_gpu_object_wait(bo, false);
232bbbed888SGerd Hoffmann 		}
233bbbed888SGerd Hoffmann 	}
234bbbed888SGerd Hoffmann 
235bbbed888SGerd Hoffmann 	if (plane->state->fb != old_state->fb) {
23686f752d2SGerd Hoffmann 		DRM_DEBUG("update, handle %d, pos +%d+%d, hot %d,%d\n", handle,
237bbbed888SGerd Hoffmann 			  plane->state->crtc_x,
23886f752d2SGerd Hoffmann 			  plane->state->crtc_y,
23986f752d2SGerd Hoffmann 			  plane->state->fb ? plane->state->fb->hot_x : 0,
24086f752d2SGerd Hoffmann 			  plane->state->fb ? plane->state->fb->hot_y : 0);
241bbbed888SGerd Hoffmann 		output->cursor.hdr.type =
242bbbed888SGerd Hoffmann 			cpu_to_le32(VIRTIO_GPU_CMD_UPDATE_CURSOR);
243bbbed888SGerd Hoffmann 		output->cursor.resource_id = cpu_to_le32(handle);
24486f752d2SGerd Hoffmann 		if (plane->state->fb) {
24586f752d2SGerd Hoffmann 			output->cursor.hot_x =
24686f752d2SGerd Hoffmann 				cpu_to_le32(plane->state->fb->hot_x);
24786f752d2SGerd Hoffmann 			output->cursor.hot_y =
24886f752d2SGerd Hoffmann 				cpu_to_le32(plane->state->fb->hot_y);
24986f752d2SGerd Hoffmann 		} else {
25086f752d2SGerd Hoffmann 			output->cursor.hot_x = cpu_to_le32(0);
25186f752d2SGerd Hoffmann 			output->cursor.hot_y = cpu_to_le32(0);
25286f752d2SGerd Hoffmann 		}
253bbbed888SGerd Hoffmann 	} else {
254bbbed888SGerd Hoffmann 		DRM_DEBUG("move +%d+%d\n",
255bbbed888SGerd Hoffmann 			  plane->state->crtc_x,
256bbbed888SGerd Hoffmann 			  plane->state->crtc_y);
257bbbed888SGerd Hoffmann 		output->cursor.hdr.type =
258bbbed888SGerd Hoffmann 			cpu_to_le32(VIRTIO_GPU_CMD_MOVE_CURSOR);
259bbbed888SGerd Hoffmann 	}
260bbbed888SGerd Hoffmann 	output->cursor.pos.x = cpu_to_le32(plane->state->crtc_x);
261bbbed888SGerd Hoffmann 	output->cursor.pos.y = cpu_to_le32(plane->state->crtc_y);
262bbbed888SGerd Hoffmann 	virtio_gpu_cursor_ping(vgdev, output);
263bbbed888SGerd Hoffmann }
264bbbed888SGerd Hoffmann 
265bbbed888SGerd Hoffmann static const struct drm_plane_helper_funcs virtio_gpu_primary_helper_funcs = {
266dc5698e8SDave Airlie 	.atomic_check		= virtio_gpu_plane_atomic_check,
267bbbed888SGerd Hoffmann 	.atomic_update		= virtio_gpu_primary_plane_update,
268bbbed888SGerd Hoffmann };
269bbbed888SGerd Hoffmann 
270bbbed888SGerd Hoffmann static const struct drm_plane_helper_funcs virtio_gpu_cursor_helper_funcs = {
271bbbed888SGerd Hoffmann 	.atomic_check		= virtio_gpu_plane_atomic_check,
272bbbed888SGerd Hoffmann 	.atomic_update		= virtio_gpu_cursor_plane_update,
273dc5698e8SDave Airlie };
274dc5698e8SDave Airlie 
275dc5698e8SDave Airlie struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev,
276bbbed888SGerd Hoffmann 					enum drm_plane_type type,
277dc5698e8SDave Airlie 					int index)
278dc5698e8SDave Airlie {
279dc5698e8SDave Airlie 	struct drm_device *dev = vgdev->ddev;
280bbbed888SGerd Hoffmann 	const struct drm_plane_helper_funcs *funcs;
281dc5698e8SDave Airlie 	struct drm_plane *plane;
282bbbed888SGerd Hoffmann 	const uint32_t *formats;
283bbbed888SGerd Hoffmann 	int ret, nformats;
284dc5698e8SDave Airlie 
285dc5698e8SDave Airlie 	plane = kzalloc(sizeof(*plane), GFP_KERNEL);
286dc5698e8SDave Airlie 	if (!plane)
287dc5698e8SDave Airlie 		return ERR_PTR(-ENOMEM);
288dc5698e8SDave Airlie 
289bbbed888SGerd Hoffmann 	if (type == DRM_PLANE_TYPE_CURSOR) {
290bbbed888SGerd Hoffmann 		formats = virtio_gpu_cursor_formats;
291bbbed888SGerd Hoffmann 		nformats = ARRAY_SIZE(virtio_gpu_cursor_formats);
292bbbed888SGerd Hoffmann 		funcs = &virtio_gpu_cursor_helper_funcs;
293bbbed888SGerd Hoffmann 	} else {
294bbbed888SGerd Hoffmann 		formats = virtio_gpu_formats;
295bbbed888SGerd Hoffmann 		nformats = ARRAY_SIZE(virtio_gpu_formats);
296bbbed888SGerd Hoffmann 		funcs = &virtio_gpu_primary_helper_funcs;
297bbbed888SGerd Hoffmann 	}
298dc5698e8SDave Airlie 	ret = drm_universal_plane_init(dev, plane, 1 << index,
299dc5698e8SDave Airlie 				       &virtio_gpu_plane_funcs,
300bbbed888SGerd Hoffmann 				       formats, nformats,
301e6fc3b68SBen Widawsky 				       NULL, type, NULL);
302dc5698e8SDave Airlie 	if (ret)
303dc5698e8SDave Airlie 		goto err_plane_init;
304dc5698e8SDave Airlie 
305bbbed888SGerd Hoffmann 	drm_plane_helper_add(plane, funcs);
306dc5698e8SDave Airlie 	return plane;
307dc5698e8SDave Airlie 
308dc5698e8SDave Airlie err_plane_init:
309dc5698e8SDave Airlie 	kfree(plane);
310dc5698e8SDave Airlie 	return ERR_PTR(ret);
311dc5698e8SDave Airlie }
312