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[] = { 42bbbed888SGerd Hoffmann DRM_FORMAT_ARGB8888, 43bbbed888SGerd Hoffmann }; 44bbbed888SGerd Hoffmann 45dc5698e8SDave Airlie static void virtio_gpu_plane_destroy(struct drm_plane *plane) 46dc5698e8SDave Airlie { 47dc5698e8SDave Airlie kfree(plane); 48dc5698e8SDave Airlie } 49dc5698e8SDave Airlie 50dc5698e8SDave Airlie static const struct drm_plane_funcs virtio_gpu_plane_funcs = { 51dc5698e8SDave Airlie .update_plane = drm_atomic_helper_update_plane, 52dc5698e8SDave Airlie .disable_plane = drm_atomic_helper_disable_plane, 53dc5698e8SDave Airlie .destroy = virtio_gpu_plane_destroy, 54dc5698e8SDave Airlie .reset = drm_atomic_helper_plane_reset, 55dc5698e8SDave Airlie .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 56dc5698e8SDave Airlie .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 57dc5698e8SDave Airlie }; 58dc5698e8SDave Airlie 59dc5698e8SDave Airlie static int virtio_gpu_plane_atomic_check(struct drm_plane *plane, 60dc5698e8SDave Airlie struct drm_plane_state *state) 61dc5698e8SDave Airlie { 62dc5698e8SDave Airlie return 0; 63dc5698e8SDave Airlie } 64dc5698e8SDave Airlie 65bbbed888SGerd Hoffmann static void virtio_gpu_primary_plane_update(struct drm_plane *plane, 66dc5698e8SDave Airlie struct drm_plane_state *old_state) 67dc5698e8SDave Airlie { 68dc5698e8SDave Airlie struct drm_device *dev = plane->dev; 69dc5698e8SDave Airlie struct virtio_gpu_device *vgdev = dev->dev_private; 70d3767d49SGerd Hoffmann struct virtio_gpu_output *output = NULL; 71dc5698e8SDave Airlie struct virtio_gpu_framebuffer *vgfb; 72dc5698e8SDave Airlie struct virtio_gpu_object *bo; 73dc5698e8SDave Airlie uint32_t handle; 74dc5698e8SDave Airlie 75d3767d49SGerd Hoffmann if (plane->state->crtc) 76d3767d49SGerd Hoffmann output = drm_crtc_to_virtio_gpu_output(plane->state->crtc); 77d3767d49SGerd Hoffmann if (old_state->crtc) 78d3767d49SGerd Hoffmann output = drm_crtc_to_virtio_gpu_output(old_state->crtc); 79b28c69ddSHeinrich Schuchardt if (WARN_ON(!output)) 80b28c69ddSHeinrich Schuchardt return; 81d3767d49SGerd Hoffmann 8211c94aceSRob Herring if (plane->state->fb) { 8311c94aceSRob Herring vgfb = to_virtio_gpu_framebuffer(plane->state->fb); 84dc5698e8SDave Airlie bo = gem_to_virtio_gpu_obj(vgfb->obj); 85dc5698e8SDave Airlie handle = bo->hw_res_handle; 864109e7f7SRob Herring if (bo->dumb) { 874109e7f7SRob Herring virtio_gpu_cmd_transfer_to_host_2d 884109e7f7SRob Herring (vgdev, handle, 0, 890062795eSGerd Hoffmann cpu_to_le32(plane->state->src_w >> 16), 900062795eSGerd Hoffmann cpu_to_le32(plane->state->src_h >> 16), 910062795eSGerd Hoffmann plane->state->src_x >> 16, 920062795eSGerd Hoffmann plane->state->src_y >> 16, NULL); 934109e7f7SRob Herring } 94dc5698e8SDave Airlie } else { 95dc5698e8SDave Airlie handle = 0; 96dc5698e8SDave Airlie } 97dc5698e8SDave Airlie 980062795eSGerd Hoffmann DRM_DEBUG("handle 0x%x, crtc %dx%d+%d+%d, src %dx%d+%d+%d\n", handle, 99dc5698e8SDave Airlie plane->state->crtc_w, plane->state->crtc_h, 1000062795eSGerd Hoffmann plane->state->crtc_x, plane->state->crtc_y, 1010062795eSGerd Hoffmann plane->state->src_w >> 16, 1020062795eSGerd Hoffmann plane->state->src_h >> 16, 1030062795eSGerd Hoffmann plane->state->src_x >> 16, 1040062795eSGerd Hoffmann plane->state->src_y >> 16); 105dc5698e8SDave Airlie virtio_gpu_cmd_set_scanout(vgdev, output->index, handle, 1060062795eSGerd Hoffmann plane->state->src_w >> 16, 1070062795eSGerd Hoffmann plane->state->src_h >> 16, 1080062795eSGerd Hoffmann plane->state->src_x >> 16, 1090062795eSGerd Hoffmann plane->state->src_y >> 16); 110bd17d1c7SRob Herring virtio_gpu_cmd_resource_flush(vgdev, handle, 1110062795eSGerd Hoffmann plane->state->src_x >> 16, 1120062795eSGerd Hoffmann plane->state->src_y >> 16, 1130062795eSGerd Hoffmann plane->state->src_w >> 16, 1140062795eSGerd Hoffmann plane->state->src_h >> 16); 115dc5698e8SDave Airlie } 116dc5698e8SDave Airlie 117bbbed888SGerd Hoffmann static void virtio_gpu_cursor_plane_update(struct drm_plane *plane, 118bbbed888SGerd Hoffmann struct drm_plane_state *old_state) 119bbbed888SGerd Hoffmann { 120bbbed888SGerd Hoffmann struct drm_device *dev = plane->dev; 121bbbed888SGerd Hoffmann struct virtio_gpu_device *vgdev = dev->dev_private; 122bbbed888SGerd Hoffmann struct virtio_gpu_output *output = NULL; 123bbbed888SGerd Hoffmann struct virtio_gpu_framebuffer *vgfb; 124bbbed888SGerd Hoffmann struct virtio_gpu_fence *fence = NULL; 125bbbed888SGerd Hoffmann struct virtio_gpu_object *bo = NULL; 126bbbed888SGerd Hoffmann uint32_t handle; 127bbbed888SGerd Hoffmann int ret = 0; 128dc5698e8SDave Airlie 129bbbed888SGerd Hoffmann if (plane->state->crtc) 130bbbed888SGerd Hoffmann output = drm_crtc_to_virtio_gpu_output(plane->state->crtc); 131bbbed888SGerd Hoffmann if (old_state->crtc) 132bbbed888SGerd Hoffmann output = drm_crtc_to_virtio_gpu_output(old_state->crtc); 133b28c69ddSHeinrich Schuchardt if (WARN_ON(!output)) 134b28c69ddSHeinrich Schuchardt return; 135bbbed888SGerd Hoffmann 136bbbed888SGerd Hoffmann if (plane->state->fb) { 137bbbed888SGerd Hoffmann vgfb = to_virtio_gpu_framebuffer(plane->state->fb); 138bbbed888SGerd Hoffmann bo = gem_to_virtio_gpu_obj(vgfb->obj); 139bbbed888SGerd Hoffmann handle = bo->hw_res_handle; 140bbbed888SGerd Hoffmann } else { 141bbbed888SGerd Hoffmann handle = 0; 142bbbed888SGerd Hoffmann } 143bbbed888SGerd Hoffmann 144bbbed888SGerd Hoffmann if (bo && bo->dumb && (plane->state->fb != old_state->fb)) { 145bbbed888SGerd Hoffmann /* new cursor -- update & wait */ 146bbbed888SGerd Hoffmann virtio_gpu_cmd_transfer_to_host_2d 147bbbed888SGerd Hoffmann (vgdev, handle, 0, 148bbbed888SGerd Hoffmann cpu_to_le32(plane->state->crtc_w), 149bbbed888SGerd Hoffmann cpu_to_le32(plane->state->crtc_h), 150bbbed888SGerd Hoffmann 0, 0, &fence); 151bbbed888SGerd Hoffmann ret = virtio_gpu_object_reserve(bo, false); 152bbbed888SGerd Hoffmann if (!ret) { 153bbbed888SGerd Hoffmann reservation_object_add_excl_fence(bo->tbo.resv, 154bbbed888SGerd Hoffmann &fence->f); 155f54d1867SChris Wilson dma_fence_put(&fence->f); 156bbbed888SGerd Hoffmann fence = NULL; 157bbbed888SGerd Hoffmann virtio_gpu_object_unreserve(bo); 158bbbed888SGerd Hoffmann virtio_gpu_object_wait(bo, false); 159bbbed888SGerd Hoffmann } 160bbbed888SGerd Hoffmann } 161bbbed888SGerd Hoffmann 162bbbed888SGerd Hoffmann if (plane->state->fb != old_state->fb) { 16386f752d2SGerd Hoffmann DRM_DEBUG("update, handle %d, pos +%d+%d, hot %d,%d\n", handle, 164bbbed888SGerd Hoffmann plane->state->crtc_x, 16586f752d2SGerd Hoffmann plane->state->crtc_y, 16686f752d2SGerd Hoffmann plane->state->fb ? plane->state->fb->hot_x : 0, 16786f752d2SGerd Hoffmann plane->state->fb ? plane->state->fb->hot_y : 0); 168bbbed888SGerd Hoffmann output->cursor.hdr.type = 169bbbed888SGerd Hoffmann cpu_to_le32(VIRTIO_GPU_CMD_UPDATE_CURSOR); 170bbbed888SGerd Hoffmann output->cursor.resource_id = cpu_to_le32(handle); 17186f752d2SGerd Hoffmann if (plane->state->fb) { 17286f752d2SGerd Hoffmann output->cursor.hot_x = 17386f752d2SGerd Hoffmann cpu_to_le32(plane->state->fb->hot_x); 17486f752d2SGerd Hoffmann output->cursor.hot_y = 17586f752d2SGerd Hoffmann cpu_to_le32(plane->state->fb->hot_y); 17686f752d2SGerd Hoffmann } else { 17786f752d2SGerd Hoffmann output->cursor.hot_x = cpu_to_le32(0); 17886f752d2SGerd Hoffmann output->cursor.hot_y = cpu_to_le32(0); 17986f752d2SGerd Hoffmann } 180bbbed888SGerd Hoffmann } else { 181bbbed888SGerd Hoffmann DRM_DEBUG("move +%d+%d\n", 182bbbed888SGerd Hoffmann plane->state->crtc_x, 183bbbed888SGerd Hoffmann plane->state->crtc_y); 184bbbed888SGerd Hoffmann output->cursor.hdr.type = 185bbbed888SGerd Hoffmann cpu_to_le32(VIRTIO_GPU_CMD_MOVE_CURSOR); 186bbbed888SGerd Hoffmann } 187bbbed888SGerd Hoffmann output->cursor.pos.x = cpu_to_le32(plane->state->crtc_x); 188bbbed888SGerd Hoffmann output->cursor.pos.y = cpu_to_le32(plane->state->crtc_y); 189bbbed888SGerd Hoffmann virtio_gpu_cursor_ping(vgdev, output); 190bbbed888SGerd Hoffmann } 191bbbed888SGerd Hoffmann 192bbbed888SGerd Hoffmann static const struct drm_plane_helper_funcs virtio_gpu_primary_helper_funcs = { 193dc5698e8SDave Airlie .atomic_check = virtio_gpu_plane_atomic_check, 194bbbed888SGerd Hoffmann .atomic_update = virtio_gpu_primary_plane_update, 195bbbed888SGerd Hoffmann }; 196bbbed888SGerd Hoffmann 197bbbed888SGerd Hoffmann static const struct drm_plane_helper_funcs virtio_gpu_cursor_helper_funcs = { 198bbbed888SGerd Hoffmann .atomic_check = virtio_gpu_plane_atomic_check, 199bbbed888SGerd Hoffmann .atomic_update = virtio_gpu_cursor_plane_update, 200dc5698e8SDave Airlie }; 201dc5698e8SDave Airlie 202dc5698e8SDave Airlie struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev, 203bbbed888SGerd Hoffmann enum drm_plane_type type, 204dc5698e8SDave Airlie int index) 205dc5698e8SDave Airlie { 206dc5698e8SDave Airlie struct drm_device *dev = vgdev->ddev; 207bbbed888SGerd Hoffmann const struct drm_plane_helper_funcs *funcs; 208dc5698e8SDave Airlie struct drm_plane *plane; 209bbbed888SGerd Hoffmann const uint32_t *formats; 210bbbed888SGerd Hoffmann int ret, nformats; 211dc5698e8SDave Airlie 212dc5698e8SDave Airlie plane = kzalloc(sizeof(*plane), GFP_KERNEL); 213dc5698e8SDave Airlie if (!plane) 214dc5698e8SDave Airlie return ERR_PTR(-ENOMEM); 215dc5698e8SDave Airlie 216bbbed888SGerd Hoffmann if (type == DRM_PLANE_TYPE_CURSOR) { 217bbbed888SGerd Hoffmann formats = virtio_gpu_cursor_formats; 218bbbed888SGerd Hoffmann nformats = ARRAY_SIZE(virtio_gpu_cursor_formats); 219bbbed888SGerd Hoffmann funcs = &virtio_gpu_cursor_helper_funcs; 220bbbed888SGerd Hoffmann } else { 221bbbed888SGerd Hoffmann formats = virtio_gpu_formats; 222bbbed888SGerd Hoffmann nformats = ARRAY_SIZE(virtio_gpu_formats); 223bbbed888SGerd Hoffmann funcs = &virtio_gpu_primary_helper_funcs; 224bbbed888SGerd Hoffmann } 225dc5698e8SDave Airlie ret = drm_universal_plane_init(dev, plane, 1 << index, 226dc5698e8SDave Airlie &virtio_gpu_plane_funcs, 227bbbed888SGerd Hoffmann formats, nformats, 228bbbed888SGerd Hoffmann type, NULL); 229dc5698e8SDave Airlie if (ret) 230dc5698e8SDave Airlie goto err_plane_init; 231dc5698e8SDave Airlie 232bbbed888SGerd Hoffmann drm_plane_helper_add(plane, funcs); 233dc5698e8SDave Airlie return plane; 234dc5698e8SDave Airlie 235dc5698e8SDave Airlie err_plane_init: 236dc5698e8SDave Airlie kfree(plane); 237dc5698e8SDave Airlie return ERR_PTR(ret); 238dc5698e8SDave Airlie } 239