Add a basic driver for virtio gpu. This allows for a video on
qemu virt machines.

Signed-off-by: Daniel Palmer <[email protected]>
---

Since the m68k virtio stuff is now in next I thought I'd send this.
This patch is based on next.

This is a very simple driver for virtio gpu that works just enough
to create a framebuffer that u-boot can use.

I've been playing with this on m68k and its shown that some of the
framebuffer code has some endian issues.

I think this is useful for testing the framebuffer code on other
arches like arm, riscv and so on.

Open to comments, ideas etc.

 drivers/virtio/Kconfig         |  19 ++
 drivers/virtio/Makefile        |   1 +
 drivers/virtio/virtio-uclass.c |   1 +
 drivers/virtio/virtio_gpu.c    | 284 ++++++++++++++++++++
 drivers/virtio/virtio_gpu.h    | 461 +++++++++++++++++++++++++++++++++
 include/virtio.h               |  10 +-
 6 files changed, 772 insertions(+), 4 deletions(-)
 create mode 100644 drivers/virtio/virtio_gpu.c
 create mode 100644 drivers/virtio/virtio_gpu.h

diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index 512ac376f185..d554346a2772 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -77,4 +77,23 @@ config VIRTIO_RNG
        help
          This is the virtual random number generator driver. It can be used
          with QEMU based targets.
+
+config VIRTIO_GPU
+       bool "virtio gpu driver"
+       depends on VIDEO
+       depends on VIRTIO
+       help
+         This is the virtual GPU driver. It can be used
+         with QEMU based targets.
+
+if VIRTIO_GPU
+config VIRTIO_DEFAULT_WIDTH
+       int "default width"
+       default 1024
+
+config VIRTIO_DEFAULT_HEIGHT
+       int "default height"
+       default 768
+endif
+
 endmenu
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
index 4c63a6c69043..c830fb6e6049 100644
--- a/drivers/virtio/Makefile
+++ b/drivers/virtio/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_VIRTIO_SANDBOX) += virtio_sandbox.o
 obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
 obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o
 obj-$(CONFIG_VIRTIO_RNG) += virtio_rng.o
+obj-$(CONFIG_VIRTIO_GPU) += virtio_gpu.o
diff --git a/drivers/virtio/virtio-uclass.c b/drivers/virtio/virtio-uclass.c
index c36e9e9b3a77..f040907e3a84 100644
--- a/drivers/virtio/virtio-uclass.c
+++ b/drivers/virtio/virtio-uclass.c
@@ -30,6 +30,7 @@ static const char *const virtio_drv_name[VIRTIO_ID_MAX_NUM] = 
{
        [VIRTIO_ID_NET]         = VIRTIO_NET_DRV_NAME,
        [VIRTIO_ID_BLOCK]       = VIRTIO_BLK_DRV_NAME,
        [VIRTIO_ID_RNG]         = VIRTIO_RNG_DRV_NAME,
+       [VIRTIO_ID_GPU]         = VIRTIO_GPU_DRV_NAME,
 };
 
 int virtio_get_config(struct udevice *vdev, unsigned int offset,
diff --git a/drivers/virtio/virtio_gpu.c b/drivers/virtio/virtio_gpu.c
new file mode 100644
index 000000000000..cd4dbc6857aa
--- /dev/null
+++ b/drivers/virtio/virtio_gpu.c
@@ -0,0 +1,284 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * virtio GPU driver
+ * 2025 Daniel Palmer <[email protected]>
+ */
+
+#include <dm.h>
+#include <malloc.h>
+#include <video.h>
+#include <virtio_types.h>
+#include <virtio.h>
+#include <virtio_ring.h>
+
+#include "virtio_gpu.h"
+
+#define VQ_CONTROL             0
+#define VQ_CURSOR              1
+#define NUM_VQS                        2
+#define FRAMEBUFFER_RESOURCE_ID        1
+
+struct virtio_gpu_priv {
+       struct virtqueue *vqs[NUM_VQS];
+};
+
+static int virtio_gpu_cmd(struct virtqueue *vq,
+                         void *req, size_t req_size,
+                         void *resp, size_t resp_size)
+{
+       struct virtio_sg resp_sg = { resp, resp_size };
+       struct virtio_sg req_sg = { req, req_size };
+       struct virtio_sg *sgs[] = { &req_sg, &resp_sg };
+       struct virtio_gpu_ctrl_hdr *resp_hdr = resp;
+       int ret;
+
+       ret = virtqueue_add(vq, sgs, 1, 1);
+       if (ret)
+               return ret;
+
+       virtqueue_kick(vq);
+
+       while (!virtqueue_get_buf(vq, NULL))
+               ;
+
+       /* Some basic error handling */
+       switch (le32_to_cpu(resp_hdr->type)) {
+       case VIRTIO_GPU_RESP_ERR_UNSPEC:
+       case VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID:
+       case VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID:
+       case VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID:
+       case VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER:
+               return -EINVAL;
+       case VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY:
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int virtio_gpu_get_display_info(struct virtqueue *vq,
+                                      struct virtio_gpu_resp_display_info 
*info)
+{
+       struct virtio_gpu_ctrl_hdr req = {
+               .type = cpu_to_le32(VIRTIO_GPU_CMD_GET_DISPLAY_INFO),
+       };
+
+       return virtio_gpu_cmd(vq, &req, sizeof(req), info, sizeof(*info));
+}
+
+static int virtio_gpu_resource_create_2d(struct virtqueue *vq,
+                                        u32 resource_id,
+                                        u32 format,
+                                        u32 width,
+                                        u32 height)
+{
+       struct virtio_gpu_resource_create_2d req = {
+               .hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_CREATE_2D),
+               .resource_id = cpu_to_le32(resource_id),
+               .format = cpu_to_le32(format),
+               .width = cpu_to_le32(width),
+               .height = cpu_to_le32(height),
+       };
+       struct virtio_gpu_ctrl_hdr resp;
+
+       return virtio_gpu_cmd(vq, &req, sizeof(req), &resp, sizeof(resp));
+}
+
+struct virtio_gpu_attach_backing_hdr_ent {
+       struct virtio_gpu_resource_attach_backing hdr;
+       struct virtio_gpu_mem_entry entry;
+};
+
+static int virtio_gpu_resource_attach_backing(struct virtqueue *vq,
+                                             u32 resource_id,
+                                             u64 addr,
+                                             u32 length)
+{
+       struct virtio_gpu_attach_backing_hdr_ent req = {
+               .hdr = {
+                       .hdr.type = 
cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING),
+                       .resource_id = cpu_to_le32(resource_id),
+                       .nr_entries = cpu_to_le32(1),
+               },
+               .entry = {
+                       .addr = cpu_to_le64(addr),
+                       .length = cpu_to_le32(length),
+               },
+       };
+       struct virtio_gpu_ctrl_hdr resp;
+
+       return virtio_gpu_cmd(vq, &req, sizeof(req), &resp, sizeof(resp));
+}
+
+static int virtio_gpu_set_scanout(struct virtqueue *vq,
+                                 u32 resource_id,
+                                 u32 width, u32 height)
+{
+       struct virtio_gpu_set_scanout req = {
+               .hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_SET_SCANOUT),
+               .resource_id = cpu_to_le32(resource_id),
+               .r = {
+                       .width = cpu_to_le32(width),
+                       .height = cpu_to_le32(height),
+               },
+       };
+       struct virtio_gpu_ctrl_hdr resp;
+
+       return virtio_gpu_cmd(vq, &req, sizeof(req), &resp, sizeof(resp));
+}
+
+static int virtio_gpu_set_transfer_to_host_2d(struct virtqueue *vq,
+                                             u32 resource_id,
+                                             u32 width,
+                                             u32 height)
+{
+       struct virtio_gpu_transfer_to_host_2d req = {
+               .hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D),
+               .resource_id = cpu_to_le32(resource_id),
+               .r = {
+                       .width = cpu_to_le32(width),
+                       .height = cpu_to_le32(height),
+               },
+       };
+       struct virtio_gpu_ctrl_hdr resp;
+
+       return virtio_gpu_cmd(vq, &req, sizeof(req), &resp, sizeof(resp));
+}
+
+static int virtio_gpu_resource_flush(struct virtqueue *vq,
+                                    u32 resource_id,
+                                    u32 width,
+                                    u32 height)
+{
+       struct virtio_gpu_resource_flush req = {
+               .hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_FLUSH),
+               .resource_id = cpu_to_le32(resource_id),
+               .r = {
+                       .width = cpu_to_le32(width),
+                       .height = cpu_to_le32(height),
+               },
+       };
+       struct virtio_gpu_ctrl_hdr resp;
+
+       return virtio_gpu_cmd(vq, &req, sizeof(req), &resp, sizeof(resp));
+}
+
+static int virtio_gpu_flush(struct udevice *dev)
+{
+       struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+       struct virtio_gpu_priv *priv = dev_get_priv(dev);
+       struct virtqueue *vq = priv->vqs[VQ_CONTROL];
+       int ret;
+
+       ret = virtio_gpu_set_transfer_to_host_2d(vq,
+                                                FRAMEBUFFER_RESOURCE_ID,
+                                                uc_priv->xsize,
+                                                uc_priv->ysize);
+       if (ret)
+               return ret;
+
+       ret = virtio_gpu_resource_flush(vq,
+                                       FRAMEBUFFER_RESOURCE_ID,
+                                       uc_priv->xsize,
+                                       uc_priv->ysize);
+
+       return ret;
+}
+
+static int virtio_gpu_probe(struct udevice *dev)
+{
+       struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+       struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+       struct virtio_gpu_priv *priv = dev_get_priv(dev);
+       struct virtio_gpu_resp_display_info display_info;
+       struct virtqueue *vq;
+       u32 width, height;
+       int ret;
+       int i;
+
+       width = CONFIG_VIRTIO_DEFAULT_WIDTH;
+       height = CONFIG_VIRTIO_DEFAULT_HEIGHT;
+
+       ret = virtio_find_vqs(dev, NUM_VQS, priv->vqs);
+       if (ret)
+               return ret;
+
+       vq = priv->vqs[VQ_CONTROL];
+
+       ret = virtio_gpu_get_display_info(vq,
+                                         &display_info);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < VIRTIO_GPU_MAX_SCANOUTS; i++) {
+               u32 h = le32_to_cpu(display_info.pmodes[i].r.height);
+               u32 w = le32_to_cpu(display_info.pmodes[i].r.width);
+               u32 e = le32_to_cpu(display_info.pmodes[i].enabled);
+
+               if (!e)
+                       continue;
+
+               /* For now just use the first enabled one */
+               width = w;
+               height = h;
+               break;
+       }
+
+       /* Just use 32 bpp rgba for now */
+       uc_priv->xsize  = width;
+       uc_priv->ysize  = height;
+       uc_priv->bpix   = VIDEO_BPP32;
+       uc_priv->format = VIDEO_RGBA8888;
+
+       ret = virtio_gpu_resource_create_2d(vq,
+                                           FRAMEBUFFER_RESOURCE_ID,
+                                           VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM,
+                                           uc_priv->xsize,
+                                           uc_priv->ysize);
+       if (ret)
+               return ret;
+
+       /* virtio GPU apparently doesn't care about alignment */
+       plat->size = (width * height) * 4;
+       plat->base = (ulong)malloc(plat->size);
+       if (!plat->base)
+               return -ENOMEM;
+
+       ret = virtio_gpu_resource_attach_backing(vq,
+                                                FRAMEBUFFER_RESOURCE_ID,
+                                                plat->base,
+                                                round_up(plat->size, 4096));
+       if (ret)
+               goto err;
+
+       ret = virtio_gpu_set_scanout(vq,
+                                    FRAMEBUFFER_RESOURCE_ID,
+                                    uc_priv->xsize,
+                                    uc_priv->ysize);
+       if (ret)
+               goto err;
+
+       /* Do an initial flush to activate the output */
+       ret = virtio_gpu_flush(dev);
+       if (ret)
+               goto err;
+
+       return 0;
+
+err:
+       free((void *)plat->base);
+       return ret;
+}
+
+static const struct video_ops virtio_gpu_ops = {
+       .video_sync = virtio_gpu_flush,
+};
+
+U_BOOT_DRIVER(virtio_gpu) = {
+       .name      = VIRTIO_GPU_DRV_NAME,
+       .id        = UCLASS_VIDEO,
+       .ops       = &virtio_gpu_ops,
+       .probe     = virtio_gpu_probe,
+       .flags     = DM_FLAG_ACTIVE_DMA,
+       .priv_auto = sizeof(struct virtio_gpu_priv),
+};
diff --git a/drivers/virtio/virtio_gpu.h b/drivers/virtio/virtio_gpu.h
new file mode 100644
index 000000000000..6732c7218ca2
--- /dev/null
+++ b/drivers/virtio/virtio_gpu.h
@@ -0,0 +1,461 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Virtio GPU Device
+ *
+ * Copyright Red Hat, Inc. 2013-2014
+ *
+ * Authors:
+ *     Dave Airlie <[email protected]>
+ *     Gerd Hoffmann <[email protected]>
+ *
+ * This header is BSD licensed so anyone can use the definitions
+ * to implement compatible drivers/servers:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef VIRTIO_GPU_HW_H
+#define VIRTIO_GPU_HW_H
+
+#include <linux/types.h>
+
+/*
+ * VIRTIO_GPU_CMD_CTX_*
+ * VIRTIO_GPU_CMD_*_3D
+ */
+#define VIRTIO_GPU_F_VIRGL               0
+
+/*
+ * VIRTIO_GPU_CMD_GET_EDID
+ */
+#define VIRTIO_GPU_F_EDID                1
+/*
+ * VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID
+ */
+#define VIRTIO_GPU_F_RESOURCE_UUID       2
+
+/*
+ * VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB
+ */
+#define VIRTIO_GPU_F_RESOURCE_BLOB       3
+/*
+ * VIRTIO_GPU_CMD_CREATE_CONTEXT with
+ * context_init and multiple timelines
+ */
+#define VIRTIO_GPU_F_CONTEXT_INIT        4
+
+enum virtio_gpu_ctrl_type {
+       VIRTIO_GPU_UNDEFINED = 0,
+
+       /* 2d commands */
+       VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100,
+       VIRTIO_GPU_CMD_RESOURCE_CREATE_2D,
+       VIRTIO_GPU_CMD_RESOURCE_UNREF,
+       VIRTIO_GPU_CMD_SET_SCANOUT,
+       VIRTIO_GPU_CMD_RESOURCE_FLUSH,
+       VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D,
+       VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING,
+       VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING,
+       VIRTIO_GPU_CMD_GET_CAPSET_INFO,
+       VIRTIO_GPU_CMD_GET_CAPSET,
+       VIRTIO_GPU_CMD_GET_EDID,
+       VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID,
+       VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB,
+       VIRTIO_GPU_CMD_SET_SCANOUT_BLOB,
+
+       /* 3d commands */
+       VIRTIO_GPU_CMD_CTX_CREATE = 0x0200,
+       VIRTIO_GPU_CMD_CTX_DESTROY,
+       VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE,
+       VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE,
+       VIRTIO_GPU_CMD_RESOURCE_CREATE_3D,
+       VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D,
+       VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D,
+       VIRTIO_GPU_CMD_SUBMIT_3D,
+       VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB,
+       VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB,
+
+       /* cursor commands */
+       VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300,
+       VIRTIO_GPU_CMD_MOVE_CURSOR,
+
+       /* success responses */
+       VIRTIO_GPU_RESP_OK_NODATA = 0x1100,
+       VIRTIO_GPU_RESP_OK_DISPLAY_INFO,
+       VIRTIO_GPU_RESP_OK_CAPSET_INFO,
+       VIRTIO_GPU_RESP_OK_CAPSET,
+       VIRTIO_GPU_RESP_OK_EDID,
+       VIRTIO_GPU_RESP_OK_RESOURCE_UUID,
+       VIRTIO_GPU_RESP_OK_MAP_INFO,
+
+       /* error responses */
+       VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200,
+       VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY,
+       VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID,
+       VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID,
+       VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID,
+       VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER,
+};
+
+enum virtio_gpu_shm_id {
+       VIRTIO_GPU_SHM_ID_UNDEFINED = 0,
+       /*
+        * VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB
+        * VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB
+        */
+       VIRTIO_GPU_SHM_ID_HOST_VISIBLE = 1
+};
+
+#define VIRTIO_GPU_FLAG_FENCE         (1 << 0)
+/*
+ * If the following flag is set, then ring_idx contains the index
+ * of the command ring that needs to used when creating the fence
+ */
+#define VIRTIO_GPU_FLAG_INFO_RING_IDX (1 << 1)
+
+struct virtio_gpu_ctrl_hdr {
+       __le32 type;
+       __le32 flags;
+       __le64 fence_id;
+       __le32 ctx_id;
+       __u8 ring_idx;
+       __u8 padding[3];
+};
+
+/* data passed in the cursor vq */
+
+struct virtio_gpu_cursor_pos {
+       __le32 scanout_id;
+       __le32 x;
+       __le32 y;
+       __le32 padding;
+};
+
+/* VIRTIO_GPU_CMD_UPDATE_CURSOR, VIRTIO_GPU_CMD_MOVE_CURSOR */
+struct virtio_gpu_update_cursor {
+       struct virtio_gpu_ctrl_hdr hdr;
+       struct virtio_gpu_cursor_pos pos;  /* update & move */
+       __le32 resource_id;           /* update only */
+       __le32 hot_x;                 /* update only */
+       __le32 hot_y;                 /* update only */
+       __le32 padding;
+};
+
+/* data passed in the control vq, 2d related */
+
+struct virtio_gpu_rect {
+       __le32 x;
+       __le32 y;
+       __le32 width;
+       __le32 height;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_UNREF */
+struct virtio_gpu_resource_unref {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __le32 resource_id;
+       __le32 padding;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: create a 2d resource with a format */
+struct virtio_gpu_resource_create_2d {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __le32 resource_id;
+       __le32 format;
+       __le32 width;
+       __le32 height;
+};
+
+/* VIRTIO_GPU_CMD_SET_SCANOUT */
+struct virtio_gpu_set_scanout {
+       struct virtio_gpu_ctrl_hdr hdr;
+       struct virtio_gpu_rect r;
+       __le32 scanout_id;
+       __le32 resource_id;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_FLUSH */
+struct virtio_gpu_resource_flush {
+       struct virtio_gpu_ctrl_hdr hdr;
+       struct virtio_gpu_rect r;
+       __le32 resource_id;
+       __le32 padding;
+};
+
+/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: simple transfer to_host */
+struct virtio_gpu_transfer_to_host_2d {
+       struct virtio_gpu_ctrl_hdr hdr;
+       struct virtio_gpu_rect r;
+       __le64 offset;
+       __le32 resource_id;
+       __le32 padding;
+};
+
+struct virtio_gpu_mem_entry {
+       __le64 addr;
+       __le32 length;
+       __le32 padding;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING */
+struct virtio_gpu_resource_attach_backing {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __le32 resource_id;
+       __le32 nr_entries;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING */
+struct virtio_gpu_resource_detach_backing {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __le32 resource_id;
+       __le32 padding;
+};
+
+/* VIRTIO_GPU_RESP_OK_DISPLAY_INFO */
+#define VIRTIO_GPU_MAX_SCANOUTS 16
+struct virtio_gpu_resp_display_info {
+       struct virtio_gpu_ctrl_hdr hdr;
+       struct virtio_gpu_display_one {
+               struct virtio_gpu_rect r;
+               __le32 enabled;
+               __le32 flags;
+       } pmodes[VIRTIO_GPU_MAX_SCANOUTS];
+};
+
+/* data passed in the control vq, 3d related */
+
+struct virtio_gpu_box {
+       __le32 x, y, z;
+       __le32 w, h, d;
+};
+
+/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D, VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D */
+struct virtio_gpu_transfer_host_3d {
+       struct virtio_gpu_ctrl_hdr hdr;
+       struct virtio_gpu_box box;
+       __le64 offset;
+       __le32 resource_id;
+       __le32 level;
+       __le32 stride;
+       __le32 layer_stride;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_CREATE_3D */
+#define VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP (1 << 0)
+struct virtio_gpu_resource_create_3d {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __le32 resource_id;
+       __le32 target;
+       __le32 format;
+       __le32 bind;
+       __le32 width;
+       __le32 height;
+       __le32 depth;
+       __le32 array_size;
+       __le32 last_level;
+       __le32 nr_samples;
+       __le32 flags;
+       __le32 padding;
+};
+
+/* VIRTIO_GPU_CMD_CTX_CREATE */
+#define VIRTIO_GPU_CONTEXT_INIT_CAPSET_ID_MASK 0x000000ff
+struct virtio_gpu_ctx_create {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __le32 nlen;
+       __le32 context_init;
+       char debug_name[64];
+};
+
+/* VIRTIO_GPU_CMD_CTX_DESTROY */
+struct virtio_gpu_ctx_destroy {
+       struct virtio_gpu_ctrl_hdr hdr;
+};
+
+/* VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE, VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE */
+struct virtio_gpu_ctx_resource {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __le32 resource_id;
+       __le32 padding;
+};
+
+/* VIRTIO_GPU_CMD_SUBMIT_3D */
+struct virtio_gpu_cmd_submit {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __le32 size;
+       __le32 padding;
+};
+
+#define VIRTIO_GPU_CAPSET_VIRGL 1
+#define VIRTIO_GPU_CAPSET_VIRGL2 2
+#define VIRTIO_GPU_CAPSET_GFXSTREAM_VULKAN 3
+#define VIRTIO_GPU_CAPSET_VENUS 4
+#define VIRTIO_GPU_CAPSET_CROSS_DOMAIN 5
+#define VIRTIO_GPU_CAPSET_DRM 6
+
+/* VIRTIO_GPU_CMD_GET_CAPSET_INFO */
+struct virtio_gpu_get_capset_info {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __le32 capset_index;
+       __le32 padding;
+};
+
+/* VIRTIO_GPU_RESP_OK_CAPSET_INFO */
+struct virtio_gpu_resp_capset_info {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __le32 capset_id;
+       __le32 capset_max_version;
+       __le32 capset_max_size;
+       __le32 padding;
+};
+
+/* VIRTIO_GPU_CMD_GET_CAPSET */
+struct virtio_gpu_get_capset {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __le32 capset_id;
+       __le32 capset_version;
+};
+
+/* VIRTIO_GPU_RESP_OK_CAPSET */
+struct virtio_gpu_resp_capset {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __u8 capset_data[];
+};
+
+/* VIRTIO_GPU_CMD_GET_EDID */
+struct virtio_gpu_cmd_get_edid {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __le32 scanout;
+       __le32 padding;
+};
+
+/* VIRTIO_GPU_RESP_OK_EDID */
+struct virtio_gpu_resp_edid {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __le32 size;
+       __le32 padding;
+       __u8 edid[1024];
+};
+
+#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0)
+
+struct virtio_gpu_config {
+       __le32 events_read;
+       __le32 events_clear;
+       __le32 num_scanouts;
+       __le32 num_capsets;
+};
+
+/* simple formats for fbcon/X use */
+enum virtio_gpu_formats {
+       VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM  = 1,
+       VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM  = 2,
+       VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM  = 3,
+       VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM  = 4,
+
+       VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM  = 67,
+       VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM  = 68,
+
+       VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM  = 121,
+       VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM  = 134,
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID */
+struct virtio_gpu_resource_assign_uuid {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __le32 resource_id;
+       __le32 padding;
+};
+
+/* VIRTIO_GPU_RESP_OK_RESOURCE_UUID */
+struct virtio_gpu_resp_resource_uuid {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __u8 uuid[16];
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB */
+struct virtio_gpu_resource_create_blob {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __le32 resource_id;
+#define VIRTIO_GPU_BLOB_MEM_GUEST             0x0001
+#define VIRTIO_GPU_BLOB_MEM_HOST3D            0x0002
+#define VIRTIO_GPU_BLOB_MEM_HOST3D_GUEST      0x0003
+
+#define VIRTIO_GPU_BLOB_FLAG_USE_MAPPABLE     0x0001
+#define VIRTIO_GPU_BLOB_FLAG_USE_SHAREABLE    0x0002
+#define VIRTIO_GPU_BLOB_FLAG_USE_CROSS_DEVICE 0x0004
+       /* zero is invalid blob mem */
+       __le32 blob_mem;
+       __le32 blob_flags;
+       __le32 nr_entries;
+       __le64 blob_id;
+       __le64 size;
+       /*
+        * sizeof(nr_entries * virtio_gpu_mem_entry) bytes follow
+        */
+};
+
+/* VIRTIO_GPU_CMD_SET_SCANOUT_BLOB */
+struct virtio_gpu_set_scanout_blob {
+       struct virtio_gpu_ctrl_hdr hdr;
+       struct virtio_gpu_rect r;
+       __le32 scanout_id;
+       __le32 resource_id;
+       __le32 width;
+       __le32 height;
+       __le32 format;
+       __le32 padding;
+       __le32 strides[4];
+       __le32 offsets[4];
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB */
+struct virtio_gpu_resource_map_blob {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __le32 resource_id;
+       __le32 padding;
+       __le64 offset;
+};
+
+/* VIRTIO_GPU_RESP_OK_MAP_INFO */
+#define VIRTIO_GPU_MAP_CACHE_MASK     0x0f
+#define VIRTIO_GPU_MAP_CACHE_NONE     0x00
+#define VIRTIO_GPU_MAP_CACHE_CACHED   0x01
+#define VIRTIO_GPU_MAP_CACHE_UNCACHED 0x02
+#define VIRTIO_GPU_MAP_CACHE_WC       0x03
+struct virtio_gpu_resp_map_info {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __u32 map_info;
+       __u32 padding;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB */
+struct virtio_gpu_resource_unmap_blob {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __le32 resource_id;
+       __le32 padding;
+};
+
+#endif
diff --git a/include/virtio.h b/include/virtio.h
index 3edf023463d7..f53158e355b1 100644
--- a/include/virtio.h
+++ b/include/virtio.h
@@ -28,14 +28,16 @@
 
 #define VIRTIO_VENDOR_QEMU     0x554d4551
 
-#define VIRTIO_ID_NET          1 /* virtio net */
-#define VIRTIO_ID_BLOCK                2 /* virtio block */
-#define VIRTIO_ID_RNG          4 /* virtio rng */
-#define VIRTIO_ID_MAX_NUM      5
+#define VIRTIO_ID_NET          1  /* virtio net */
+#define VIRTIO_ID_BLOCK                2  /* virtio block */
+#define VIRTIO_ID_RNG          4  /* virtio rng */
+#define VIRTIO_ID_GPU          16 /* virtio gpu */
+#define VIRTIO_ID_MAX_NUM      17
 
 #define VIRTIO_NET_DRV_NAME    "virtio-net"
 #define VIRTIO_BLK_DRV_NAME    "virtio-blk"
 #define VIRTIO_RNG_DRV_NAME    "virtio-rng"
+#define VIRTIO_GPU_DRV_NAME    "virtio-gpu"
 
 /* Status byte for guest to report progress, and synchronize features */
 
-- 
2.53.0

Reply via email to