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[] = { 3142fd9e6cSGerd Hoffmann DRM_FORMAT_HOST_XRGB8888, 32dc5698e8SDave Airlie }; 33dc5698e8SDave Airlie 34bbbed888SGerd Hoffmann static const uint32_t virtio_gpu_cursor_formats[] = { 3542fd9e6cSGerd Hoffmann DRM_FORMAT_HOST_ARGB8888, 36bbbed888SGerd Hoffmann }; 37bbbed888SGerd Hoffmann 38d519cb76SGerd Hoffmann uint32_t virtio_gpu_translate_format(uint32_t drm_fourcc) 39d519cb76SGerd Hoffmann { 40d519cb76SGerd Hoffmann uint32_t format; 41d519cb76SGerd Hoffmann 42d519cb76SGerd Hoffmann switch (drm_fourcc) { 43d519cb76SGerd Hoffmann case DRM_FORMAT_XRGB8888: 44d519cb76SGerd Hoffmann format = VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM; 45d519cb76SGerd Hoffmann break; 46d519cb76SGerd Hoffmann case DRM_FORMAT_ARGB8888: 47d519cb76SGerd Hoffmann format = VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM; 48d519cb76SGerd Hoffmann break; 49d519cb76SGerd Hoffmann case DRM_FORMAT_BGRX8888: 50d519cb76SGerd Hoffmann format = VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM; 51d519cb76SGerd Hoffmann break; 52d519cb76SGerd Hoffmann case DRM_FORMAT_BGRA8888: 53d519cb76SGerd Hoffmann format = VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM; 54d519cb76SGerd Hoffmann break; 55d519cb76SGerd Hoffmann default: 56d519cb76SGerd Hoffmann /* 57d519cb76SGerd Hoffmann * This should not happen, we handle everything listed 58d519cb76SGerd Hoffmann * in virtio_gpu_formats[]. 59d519cb76SGerd Hoffmann */ 60d519cb76SGerd Hoffmann format = 0; 61d519cb76SGerd Hoffmann break; 62d519cb76SGerd Hoffmann } 63d519cb76SGerd Hoffmann WARN_ON(format == 0); 64d519cb76SGerd Hoffmann return format; 65d519cb76SGerd Hoffmann } 66d519cb76SGerd Hoffmann 67dc5698e8SDave Airlie static void virtio_gpu_plane_destroy(struct drm_plane *plane) 68dc5698e8SDave Airlie { 69fb70046cSGustavo Padovan drm_plane_cleanup(plane); 70dc5698e8SDave Airlie kfree(plane); 71dc5698e8SDave Airlie } 72dc5698e8SDave Airlie 73dc5698e8SDave Airlie static const struct drm_plane_funcs virtio_gpu_plane_funcs = { 74dc5698e8SDave Airlie .update_plane = drm_atomic_helper_update_plane, 75dc5698e8SDave Airlie .disable_plane = drm_atomic_helper_disable_plane, 76dc5698e8SDave Airlie .destroy = virtio_gpu_plane_destroy, 77dc5698e8SDave Airlie .reset = drm_atomic_helper_plane_reset, 78dc5698e8SDave Airlie .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 79dc5698e8SDave Airlie .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 80dc5698e8SDave Airlie }; 81dc5698e8SDave Airlie 82dc5698e8SDave Airlie static int virtio_gpu_plane_atomic_check(struct drm_plane *plane, 83dc5698e8SDave Airlie struct drm_plane_state *state) 84dc5698e8SDave Airlie { 85dc5698e8SDave Airlie return 0; 86dc5698e8SDave Airlie } 87dc5698e8SDave Airlie 88bbbed888SGerd Hoffmann static void virtio_gpu_primary_plane_update(struct drm_plane *plane, 89dc5698e8SDave Airlie struct drm_plane_state *old_state) 90dc5698e8SDave Airlie { 91dc5698e8SDave Airlie struct drm_device *dev = plane->dev; 92dc5698e8SDave Airlie struct virtio_gpu_device *vgdev = dev->dev_private; 93d3767d49SGerd Hoffmann struct virtio_gpu_output *output = NULL; 94dc5698e8SDave Airlie struct virtio_gpu_framebuffer *vgfb; 95dc5698e8SDave Airlie struct virtio_gpu_object *bo; 96dc5698e8SDave Airlie uint32_t handle; 97dc5698e8SDave Airlie 98d3767d49SGerd Hoffmann if (plane->state->crtc) 99d3767d49SGerd Hoffmann output = drm_crtc_to_virtio_gpu_output(plane->state->crtc); 100d3767d49SGerd Hoffmann if (old_state->crtc) 101d3767d49SGerd Hoffmann output = drm_crtc_to_virtio_gpu_output(old_state->crtc); 102b28c69ddSHeinrich Schuchardt if (WARN_ON(!output)) 103b28c69ddSHeinrich Schuchardt return; 104d3767d49SGerd Hoffmann 1056c19787eSGerd Hoffmann if (plane->state->fb && output->enabled) { 10611c94aceSRob Herring vgfb = to_virtio_gpu_framebuffer(plane->state->fb); 1073823da3aSDaniel Stone bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]); 108dc5698e8SDave Airlie handle = bo->hw_res_handle; 1094109e7f7SRob Herring if (bo->dumb) { 1104109e7f7SRob Herring virtio_gpu_cmd_transfer_to_host_2d 111af334c5dSGerd Hoffmann (vgdev, bo, 0, 1120062795eSGerd Hoffmann cpu_to_le32(plane->state->src_w >> 16), 1130062795eSGerd Hoffmann cpu_to_le32(plane->state->src_h >> 16), 1148854a56fSMichael S. Tsirkin cpu_to_le32(plane->state->src_x >> 16), 1158854a56fSMichael S. Tsirkin cpu_to_le32(plane->state->src_y >> 16), NULL); 1164109e7f7SRob Herring } 117dc5698e8SDave Airlie } else { 118dc5698e8SDave Airlie handle = 0; 119dc5698e8SDave Airlie } 120dc5698e8SDave Airlie 1210062795eSGerd Hoffmann DRM_DEBUG("handle 0x%x, crtc %dx%d+%d+%d, src %dx%d+%d+%d\n", handle, 122dc5698e8SDave Airlie plane->state->crtc_w, plane->state->crtc_h, 1230062795eSGerd Hoffmann plane->state->crtc_x, plane->state->crtc_y, 1240062795eSGerd Hoffmann plane->state->src_w >> 16, 1250062795eSGerd Hoffmann plane->state->src_h >> 16, 1260062795eSGerd Hoffmann plane->state->src_x >> 16, 1270062795eSGerd Hoffmann plane->state->src_y >> 16); 128dc5698e8SDave Airlie virtio_gpu_cmd_set_scanout(vgdev, output->index, handle, 1290062795eSGerd Hoffmann plane->state->src_w >> 16, 1300062795eSGerd Hoffmann plane->state->src_h >> 16, 1310062795eSGerd Hoffmann plane->state->src_x >> 16, 1320062795eSGerd Hoffmann plane->state->src_y >> 16); 1336a01d277SGerd Hoffmann if (handle) 134bd17d1c7SRob Herring virtio_gpu_cmd_resource_flush(vgdev, handle, 1350062795eSGerd Hoffmann plane->state->src_x >> 16, 1360062795eSGerd Hoffmann plane->state->src_y >> 16, 1370062795eSGerd Hoffmann plane->state->src_w >> 16, 1380062795eSGerd Hoffmann plane->state->src_h >> 16); 139dc5698e8SDave Airlie } 140dc5698e8SDave Airlie 1419fdd90c0SRobert Foss static int virtio_gpu_cursor_prepare_fb(struct drm_plane *plane, 1429fdd90c0SRobert Foss struct drm_plane_state *new_state) 1439fdd90c0SRobert Foss { 1449fdd90c0SRobert Foss struct drm_device *dev = plane->dev; 1459fdd90c0SRobert Foss struct virtio_gpu_device *vgdev = dev->dev_private; 1469fdd90c0SRobert Foss struct virtio_gpu_framebuffer *vgfb; 1479fdd90c0SRobert Foss struct virtio_gpu_object *bo; 1489fdd90c0SRobert Foss 1499fdd90c0SRobert Foss if (!new_state->fb) 1509fdd90c0SRobert Foss return 0; 1519fdd90c0SRobert Foss 1529fdd90c0SRobert Foss vgfb = to_virtio_gpu_framebuffer(new_state->fb); 1539fdd90c0SRobert Foss bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]); 1549fdd90c0SRobert Foss if (bo && bo->dumb && (plane->state->fb != new_state->fb)) { 1559fdd90c0SRobert Foss vgfb->fence = virtio_gpu_fence_alloc(vgdev); 1569fdd90c0SRobert Foss if (!vgfb->fence) 1579fdd90c0SRobert Foss return -ENOMEM; 1589fdd90c0SRobert Foss } 1599fdd90c0SRobert Foss 1609fdd90c0SRobert Foss return 0; 1619fdd90c0SRobert Foss } 1629fdd90c0SRobert Foss 1639fdd90c0SRobert Foss static void virtio_gpu_cursor_cleanup_fb(struct drm_plane *plane, 1649fdd90c0SRobert Foss struct drm_plane_state *old_state) 1659fdd90c0SRobert Foss { 1669fdd90c0SRobert Foss struct virtio_gpu_framebuffer *vgfb; 1679fdd90c0SRobert Foss 1689fdd90c0SRobert Foss if (!plane->state->fb) 1699fdd90c0SRobert Foss return; 1709fdd90c0SRobert Foss 1719fdd90c0SRobert Foss vgfb = to_virtio_gpu_framebuffer(plane->state->fb); 1729fdd90c0SRobert Foss if (vgfb->fence) 1739fdd90c0SRobert Foss virtio_gpu_fence_cleanup(vgfb->fence); 1749fdd90c0SRobert Foss } 1759fdd90c0SRobert Foss 176bbbed888SGerd Hoffmann static void virtio_gpu_cursor_plane_update(struct drm_plane *plane, 177bbbed888SGerd Hoffmann struct drm_plane_state *old_state) 178bbbed888SGerd Hoffmann { 179bbbed888SGerd Hoffmann struct drm_device *dev = plane->dev; 180bbbed888SGerd Hoffmann struct virtio_gpu_device *vgdev = dev->dev_private; 181bbbed888SGerd Hoffmann struct virtio_gpu_output *output = NULL; 182bbbed888SGerd Hoffmann struct virtio_gpu_framebuffer *vgfb; 183bbbed888SGerd Hoffmann struct virtio_gpu_object *bo = NULL; 184bbbed888SGerd Hoffmann uint32_t handle; 185bbbed888SGerd Hoffmann int ret = 0; 186dc5698e8SDave Airlie 187bbbed888SGerd Hoffmann if (plane->state->crtc) 188bbbed888SGerd Hoffmann output = drm_crtc_to_virtio_gpu_output(plane->state->crtc); 189bbbed888SGerd Hoffmann if (old_state->crtc) 190bbbed888SGerd Hoffmann output = drm_crtc_to_virtio_gpu_output(old_state->crtc); 191b28c69ddSHeinrich Schuchardt if (WARN_ON(!output)) 192b28c69ddSHeinrich Schuchardt return; 193bbbed888SGerd Hoffmann 194bbbed888SGerd Hoffmann if (plane->state->fb) { 195bbbed888SGerd Hoffmann vgfb = to_virtio_gpu_framebuffer(plane->state->fb); 1963823da3aSDaniel Stone bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]); 197bbbed888SGerd Hoffmann handle = bo->hw_res_handle; 198bbbed888SGerd Hoffmann } else { 199bbbed888SGerd Hoffmann handle = 0; 200bbbed888SGerd Hoffmann } 201bbbed888SGerd Hoffmann 202bbbed888SGerd Hoffmann if (bo && bo->dumb && (plane->state->fb != old_state->fb)) { 203bbbed888SGerd Hoffmann /* new cursor -- update & wait */ 204bbbed888SGerd Hoffmann virtio_gpu_cmd_transfer_to_host_2d 205af334c5dSGerd Hoffmann (vgdev, bo, 0, 206bbbed888SGerd Hoffmann cpu_to_le32(plane->state->crtc_w), 207bbbed888SGerd Hoffmann cpu_to_le32(plane->state->crtc_h), 2084d55fd66SGerd Hoffmann 0, 0, vgfb->fence); 209bbbed888SGerd Hoffmann ret = virtio_gpu_object_reserve(bo, false); 210bbbed888SGerd Hoffmann if (!ret) { 211bbbed888SGerd Hoffmann reservation_object_add_excl_fence(bo->tbo.resv, 2129fdd90c0SRobert Foss &vgfb->fence->f); 2139fdd90c0SRobert Foss dma_fence_put(&vgfb->fence->f); 2149fdd90c0SRobert Foss vgfb->fence = NULL; 215bbbed888SGerd Hoffmann virtio_gpu_object_unreserve(bo); 216bbbed888SGerd Hoffmann virtio_gpu_object_wait(bo, false); 217bbbed888SGerd Hoffmann } 218bbbed888SGerd Hoffmann } 219bbbed888SGerd Hoffmann 220bbbed888SGerd Hoffmann if (plane->state->fb != old_state->fb) { 22186f752d2SGerd Hoffmann DRM_DEBUG("update, handle %d, pos +%d+%d, hot %d,%d\n", handle, 222bbbed888SGerd Hoffmann plane->state->crtc_x, 22386f752d2SGerd Hoffmann plane->state->crtc_y, 22486f752d2SGerd Hoffmann plane->state->fb ? plane->state->fb->hot_x : 0, 22586f752d2SGerd Hoffmann plane->state->fb ? plane->state->fb->hot_y : 0); 226bbbed888SGerd Hoffmann output->cursor.hdr.type = 227bbbed888SGerd Hoffmann cpu_to_le32(VIRTIO_GPU_CMD_UPDATE_CURSOR); 228bbbed888SGerd Hoffmann output->cursor.resource_id = cpu_to_le32(handle); 22986f752d2SGerd Hoffmann if (plane->state->fb) { 23086f752d2SGerd Hoffmann output->cursor.hot_x = 23186f752d2SGerd Hoffmann cpu_to_le32(plane->state->fb->hot_x); 23286f752d2SGerd Hoffmann output->cursor.hot_y = 23386f752d2SGerd Hoffmann cpu_to_le32(plane->state->fb->hot_y); 23486f752d2SGerd Hoffmann } else { 23586f752d2SGerd Hoffmann output->cursor.hot_x = cpu_to_le32(0); 23686f752d2SGerd Hoffmann output->cursor.hot_y = cpu_to_le32(0); 23786f752d2SGerd Hoffmann } 238bbbed888SGerd Hoffmann } else { 239bbbed888SGerd Hoffmann DRM_DEBUG("move +%d+%d\n", 240bbbed888SGerd Hoffmann plane->state->crtc_x, 241bbbed888SGerd Hoffmann plane->state->crtc_y); 242bbbed888SGerd Hoffmann output->cursor.hdr.type = 243bbbed888SGerd Hoffmann cpu_to_le32(VIRTIO_GPU_CMD_MOVE_CURSOR); 244bbbed888SGerd Hoffmann } 245bbbed888SGerd Hoffmann output->cursor.pos.x = cpu_to_le32(plane->state->crtc_x); 246bbbed888SGerd Hoffmann output->cursor.pos.y = cpu_to_le32(plane->state->crtc_y); 247bbbed888SGerd Hoffmann virtio_gpu_cursor_ping(vgdev, output); 248bbbed888SGerd Hoffmann } 249bbbed888SGerd Hoffmann 250bbbed888SGerd Hoffmann static const struct drm_plane_helper_funcs virtio_gpu_primary_helper_funcs = { 251dc5698e8SDave Airlie .atomic_check = virtio_gpu_plane_atomic_check, 252bbbed888SGerd Hoffmann .atomic_update = virtio_gpu_primary_plane_update, 253bbbed888SGerd Hoffmann }; 254bbbed888SGerd Hoffmann 255bbbed888SGerd Hoffmann static const struct drm_plane_helper_funcs virtio_gpu_cursor_helper_funcs = { 2569fdd90c0SRobert Foss .prepare_fb = virtio_gpu_cursor_prepare_fb, 2579fdd90c0SRobert Foss .cleanup_fb = virtio_gpu_cursor_cleanup_fb, 258bbbed888SGerd Hoffmann .atomic_check = virtio_gpu_plane_atomic_check, 259bbbed888SGerd Hoffmann .atomic_update = virtio_gpu_cursor_plane_update, 260dc5698e8SDave Airlie }; 261dc5698e8SDave Airlie 262dc5698e8SDave Airlie struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev, 263bbbed888SGerd Hoffmann enum drm_plane_type type, 264dc5698e8SDave Airlie int index) 265dc5698e8SDave Airlie { 266dc5698e8SDave Airlie struct drm_device *dev = vgdev->ddev; 267bbbed888SGerd Hoffmann const struct drm_plane_helper_funcs *funcs; 268dc5698e8SDave Airlie struct drm_plane *plane; 269bbbed888SGerd Hoffmann const uint32_t *formats; 270bbbed888SGerd Hoffmann int ret, nformats; 271dc5698e8SDave Airlie 272dc5698e8SDave Airlie plane = kzalloc(sizeof(*plane), GFP_KERNEL); 273dc5698e8SDave Airlie if (!plane) 274dc5698e8SDave Airlie return ERR_PTR(-ENOMEM); 275dc5698e8SDave Airlie 276bbbed888SGerd Hoffmann if (type == DRM_PLANE_TYPE_CURSOR) { 277bbbed888SGerd Hoffmann formats = virtio_gpu_cursor_formats; 278bbbed888SGerd Hoffmann nformats = ARRAY_SIZE(virtio_gpu_cursor_formats); 279bbbed888SGerd Hoffmann funcs = &virtio_gpu_cursor_helper_funcs; 280bbbed888SGerd Hoffmann } else { 281bbbed888SGerd Hoffmann formats = virtio_gpu_formats; 282bbbed888SGerd Hoffmann nformats = ARRAY_SIZE(virtio_gpu_formats); 283bbbed888SGerd Hoffmann funcs = &virtio_gpu_primary_helper_funcs; 284bbbed888SGerd Hoffmann } 285dc5698e8SDave Airlie ret = drm_universal_plane_init(dev, plane, 1 << index, 286dc5698e8SDave Airlie &virtio_gpu_plane_funcs, 287bbbed888SGerd Hoffmann formats, nformats, 288e6fc3b68SBen Widawsky NULL, type, NULL); 289dc5698e8SDave Airlie if (ret) 290dc5698e8SDave Airlie goto err_plane_init; 291dc5698e8SDave Airlie 292bbbed888SGerd Hoffmann drm_plane_helper_add(plane, funcs); 293dc5698e8SDave Airlie return plane; 294dc5698e8SDave Airlie 295dc5698e8SDave Airlie err_plane_init: 296dc5698e8SDave Airlie kfree(plane); 297dc5698e8SDave Airlie return ERR_PTR(ret); 298dc5698e8SDave Airlie } 299