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