[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/bsp/lk/dev/virtio/gpu/include/dev/virtio/gpu.h b/src/bsp/lk/dev/virtio/gpu/include/dev/virtio/gpu.h
new file mode 100644
index 0000000..2300697
--- /dev/null
+++ b/src/bsp/lk/dev/virtio/gpu/include/dev/virtio/gpu.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#pragma once
+
+#include <compiler.h>
+#include <sys/types.h>
+#include <dev/virtio.h>
+
+status_t virtio_gpu_init(struct virtio_device *dev, uint32_t host_features) __NONNULL();
+
+status_t virtio_gpu_start(struct virtio_device *dev) __NONNULL();
+
diff --git a/src/bsp/lk/dev/virtio/gpu/rules.mk b/src/bsp/lk/dev/virtio/gpu/rules.mk
new file mode 100644
index 0000000..8210208
--- /dev/null
+++ b/src/bsp/lk/dev/virtio/gpu/rules.mk
@@ -0,0 +1,12 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS += \
+	$(LOCAL_DIR)/virtio-gpu.c \
+
+MODULE_DEPS += \
+	dev/virtio \
+	lib/gfx
+
+include make/module.mk
diff --git a/src/bsp/lk/dev/virtio/gpu/virtio-gpu.c b/src/bsp/lk/dev/virtio/gpu/virtio-gpu.c
new file mode 100644
index 0000000..d9b24c7
--- /dev/null
+++ b/src/bsp/lk/dev/virtio/gpu/virtio-gpu.c
@@ -0,0 +1,577 @@
+/*
+ * Copyright (c) 2014-2015 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <dev/virtio/gpu.h>
+
+#include <debug.h>
+#include <assert.h>
+#include <trace.h>
+#include <compiler.h>
+#include <list.h>
+#include <err.h>
+#include <string.h>
+#include <kernel/thread.h>
+#include <kernel/event.h>
+#include <kernel/mutex.h>
+#include <kernel/vm.h>
+#include <lib/gfx.h>
+#include <dev/display.h>
+
+#include "virtio_gpu.h"
+
+#define LOCAL_TRACE 0
+
+static enum handler_return virtio_gpu_irq_driver_callback(struct virtio_device *dev, uint ring, const struct vring_used_elem *e);
+static enum handler_return virtio_gpu_config_change_callback(struct virtio_device *dev);
+static int virtio_gpu_flush_thread(void *arg);
+
+struct virtio_gpu_dev {
+    struct virtio_device *dev;
+
+    mutex_t lock;
+    event_t io_event;
+
+    void *gpu_request;
+    paddr_t gpu_request_phys;
+
+    /* a saved copy of the display */
+    struct virtio_gpu_display_one pmode;
+    int pmode_id;
+
+    /* resource id that is set as scanout */
+    uint32_t display_resource_id;
+
+    /* next resource id */
+    uint32_t next_resource_id;
+
+    event_t flush_event;
+
+    /* framebuffer */
+    void *fb;
+};
+
+static struct virtio_gpu_dev *the_gdev;
+
+static status_t send_command_response(struct virtio_gpu_dev *gdev, const void *cmd, size_t cmd_len, void **_res, size_t res_len)
+{
+    DEBUG_ASSERT(gdev);
+    DEBUG_ASSERT(cmd);
+    DEBUG_ASSERT(_res);
+    DEBUG_ASSERT(cmd_len + res_len < PAGE_SIZE);
+
+    LTRACEF("gdev %p, cmd %p, cmd_len %zu, res %p, res_len %zu\n", gdev, cmd, cmd_len, _res, res_len);
+
+    uint16_t i;
+    struct vring_desc *desc = virtio_alloc_desc_chain(gdev->dev, 0, 2, &i);
+    DEBUG_ASSERT(desc);
+
+    memcpy(gdev->gpu_request, cmd, cmd_len);
+
+    desc->addr = gdev->gpu_request_phys;
+    desc->len = cmd_len;
+    desc->flags |= VRING_DESC_F_NEXT;
+
+    /* set the second descriptor to the response with the write bit set */
+    desc = virtio_desc_index_to_desc(gdev->dev, 0, desc->next);
+    DEBUG_ASSERT(desc);
+
+    void *res = (void *)((uint8_t *)gdev->gpu_request + cmd_len);
+    *_res = res;
+    paddr_t res_phys = gdev->gpu_request_phys + cmd_len;
+    memset(res, 0, res_len);
+
+    desc->addr = res_phys;
+    desc->len = res_len;
+    desc->flags = VRING_DESC_F_WRITE;
+
+    /* submit the transfer */
+    virtio_submit_chain(gdev->dev, 0, i);
+
+    /* kick it off */
+    virtio_kick(gdev->dev, 0);
+
+    /* wait for result */
+    event_wait(&gdev->io_event);
+
+    return NO_ERROR;
+}
+
+static status_t get_display_info(struct virtio_gpu_dev *gdev)
+{
+    status_t err;
+
+    LTRACEF("gdev %p\n", gdev);
+
+    DEBUG_ASSERT(gdev);
+
+    /* grab a lock to keep this single message at a time */
+    mutex_acquire(&gdev->lock);
+
+    /* construct the get display info message */
+    struct virtio_gpu_ctrl_hdr req;
+    memset(&req, 0, sizeof(req));
+    req.type = VIRTIO_GPU_CMD_GET_DISPLAY_INFO;
+
+    /* send the message and get a response */
+    struct virtio_gpu_resp_display_info *info;
+    err = send_command_response(gdev, &req, sizeof(req), (void **)&info, sizeof(*info));
+    DEBUG_ASSERT(err == NO_ERROR);
+    if (err < NO_ERROR) {
+        mutex_release(&gdev->lock);
+        return ERR_NOT_FOUND;
+    }
+
+    /* we got response */
+    if (info->hdr.type != VIRTIO_GPU_RESP_OK_DISPLAY_INFO) {
+        mutex_release(&gdev->lock);
+        return ERR_NOT_FOUND;
+    }
+
+    LTRACEF("response:\n");
+    for (uint i = 0; i < VIRTIO_GPU_MAX_SCANOUTS; i++) {
+        if (info->pmodes[i].enabled) {
+            LTRACEF("%u: x %u y %u w %u h %u flags 0x%x\n", i,
+                    info->pmodes[i].r.x, info->pmodes[i].r.y, info->pmodes[i].r.width, info->pmodes[i].r.height,
+                    info->pmodes[i].flags);
+            if (gdev->pmode_id < 0) {
+                /* save the first valid pmode we see */
+                memcpy(&gdev->pmode, &info->pmodes[i], sizeof(gdev->pmode));
+                gdev->pmode_id = i;
+            }
+        }
+    }
+
+    /* release the lock */
+    mutex_release(&gdev->lock);
+
+    return NO_ERROR;
+}
+
+static status_t allocate_2d_resource(struct virtio_gpu_dev *gdev, uint32_t *resource_id, uint32_t width, uint32_t height)
+{
+    status_t err;
+
+    LTRACEF("gdev %p\n", gdev);
+
+    DEBUG_ASSERT(gdev);
+    DEBUG_ASSERT(resource_id);
+
+    /* grab a lock to keep this single message at a time */
+    mutex_acquire(&gdev->lock);
+
+    /* construct the request */
+    struct virtio_gpu_resource_create_2d req;
+    memset(&req, 0, sizeof(req));
+
+    req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_CREATE_2D;
+    req.resource_id = gdev->next_resource_id++;
+    *resource_id = req.resource_id;
+    req.format = VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM;
+    req.width = width;
+    req.height = height;
+
+    /* send the command and get a response */
+    struct virtio_gpu_ctrl_hdr *res;
+    err = send_command_response(gdev, &req, sizeof(req), (void **)&res, sizeof(*res));
+    DEBUG_ASSERT(err == NO_ERROR);
+
+    /* see if we got a valid response */
+    LTRACEF("response type 0x%x\n", res->type);
+    err = (res->type == VIRTIO_GPU_RESP_OK_NODATA) ? NO_ERROR : ERR_NO_MEMORY;
+
+    /* release the lock */
+    mutex_release(&gdev->lock);
+
+    return err;
+}
+
+static status_t attach_backing(struct virtio_gpu_dev *gdev, uint32_t resource_id, void *ptr, size_t buf_len)
+{
+    status_t err;
+
+    LTRACEF("gdev %p, resource_id %u, ptr %p, buf_len %zu\n", gdev, resource_id, ptr, buf_len);
+
+    DEBUG_ASSERT(gdev);
+    DEBUG_ASSERT(ptr);
+
+    /* grab a lock to keep this single message at a time */
+    mutex_acquire(&gdev->lock);
+
+    /* construct the request */
+    struct {
+        struct virtio_gpu_resource_attach_backing req;
+        struct virtio_gpu_mem_entry mem;
+    } req;
+    memset(&req, 0, sizeof(req));
+
+    req.req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING;
+    req.req.resource_id = resource_id;
+    req.req.nr_entries = 1;
+
+    paddr_t pa;
+    arch_mmu_query((vaddr_t)ptr, &pa, NULL);
+    req.mem.addr = pa;
+    req.mem.length = buf_len;
+
+    /* send the command and get a response */
+    struct virtio_gpu_ctrl_hdr *res;
+    err = send_command_response(gdev, &req, sizeof(req), (void **)&res, sizeof(*res));
+    DEBUG_ASSERT(err == NO_ERROR);
+
+    /* see if we got a valid response */
+    LTRACEF("response type 0x%x\n", res->type);
+    err = (res->type == VIRTIO_GPU_RESP_OK_NODATA) ? NO_ERROR : ERR_NO_MEMORY;
+
+    /* release the lock */
+    mutex_release(&gdev->lock);
+
+    return err;
+}
+
+static status_t set_scanout(struct virtio_gpu_dev *gdev, uint32_t scanout_id, uint32_t resource_id, uint32_t width, uint32_t height)
+{
+    status_t err;
+
+    LTRACEF("gdev %p, scanout_id %u, resource_id %u, width %u, height %u\n", gdev, scanout_id, resource_id, width, height);
+
+    /* grab a lock to keep this single message at a time */
+    mutex_acquire(&gdev->lock);
+
+    /* construct the request */
+    struct virtio_gpu_set_scanout req;
+    memset(&req, 0, sizeof(req));
+
+    req.hdr.type = VIRTIO_GPU_CMD_SET_SCANOUT;
+    req.r.x = req.r.y = 0;
+    req.r.width = width;
+    req.r.height = height;
+    req.scanout_id = scanout_id;
+    req.resource_id = resource_id;
+
+    /* send the command and get a response */
+    struct virtio_gpu_ctrl_hdr *res;
+    err = send_command_response(gdev, &req, sizeof(req), (void **)&res, sizeof(*res));
+    DEBUG_ASSERT(err == NO_ERROR);
+
+    /* see if we got a valid response */
+    LTRACEF("response type 0x%x\n", res->type);
+    err = (res->type == VIRTIO_GPU_RESP_OK_NODATA) ? NO_ERROR : ERR_NO_MEMORY;
+
+    /* release the lock */
+    mutex_release(&gdev->lock);
+
+    return err;
+}
+
+static status_t flush_resource(struct virtio_gpu_dev *gdev, uint32_t resource_id, uint32_t width, uint32_t height)
+{
+    status_t err;
+
+    LTRACEF("gdev %p, resource_id %u, width %u, height %u\n", gdev, resource_id, width, height);
+
+    /* grab a lock to keep this single message at a time */
+    mutex_acquire(&gdev->lock);
+
+    /* construct the request */
+    struct virtio_gpu_resource_flush req;
+    memset(&req, 0, sizeof(req));
+
+    req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_FLUSH;
+    req.r.x = req.r.y = 0;
+    req.r.width = width;
+    req.r.height = height;
+    req.resource_id = resource_id;
+
+    /* send the command and get a response */
+    struct virtio_gpu_ctrl_hdr *res;
+    err = send_command_response(gdev, &req, sizeof(req), (void **)&res, sizeof(*res));
+    DEBUG_ASSERT(err == NO_ERROR);
+
+    /* see if we got a valid response */
+    LTRACEF("response type 0x%x\n", res->type);
+    err = (res->type == VIRTIO_GPU_RESP_OK_NODATA) ? NO_ERROR : ERR_NO_MEMORY;
+
+    /* release the lock */
+    mutex_release(&gdev->lock);
+
+    return err;
+}
+
+static status_t transfer_to_host_2d(struct virtio_gpu_dev *gdev, uint32_t resource_id, uint32_t width, uint32_t height)
+{
+    status_t err;
+
+    LTRACEF("gdev %p, resource_id %u, width %u, height %u\n", gdev, resource_id, width, height);
+
+    /* grab a lock to keep this single message at a time */
+    mutex_acquire(&gdev->lock);
+
+    /* construct the request */
+    struct virtio_gpu_transfer_to_host_2d req;
+    memset(&req, 0, sizeof(req));
+
+    req.hdr.type = VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D;
+    req.r.x = req.r.y = 0;
+    req.r.width = width;
+    req.r.height = height;
+    req.offset = 0;
+    req.resource_id = resource_id;
+
+    /* send the command and get a response */
+    struct virtio_gpu_ctrl_hdr *res;
+    err = send_command_response(gdev, &req, sizeof(req), (void **)&res, sizeof(*res));
+    DEBUG_ASSERT(err == NO_ERROR);
+
+    /* see if we got a valid response */
+    LTRACEF("response type 0x%x\n", res->type);
+    err = (res->type == VIRTIO_GPU_RESP_OK_NODATA) ? NO_ERROR : ERR_NO_MEMORY;
+
+    /* release the lock */
+    mutex_release(&gdev->lock);
+
+    return err;
+}
+
+status_t virtio_gpu_start(struct virtio_device *dev)
+{
+    status_t err;
+
+    LTRACEF("dev %p\n", dev);
+
+    struct virtio_gpu_dev *gdev = (struct virtio_gpu_dev *)dev->priv;
+
+    /* get the display info and see if we find a valid pmode */
+    err = get_display_info(gdev);
+    if (err < 0) {
+        LTRACEF("failed to get display info\n");
+        return err;
+    }
+
+    if (gdev->pmode_id < 0) {
+        LTRACEF("we failed to find a pmode, exiting\n");
+        return ERR_NOT_FOUND;
+    }
+
+    /* allocate a resource */
+    err = allocate_2d_resource(gdev, &gdev->display_resource_id, gdev->pmode.r.width, gdev->pmode.r.height);
+    if (err < 0) {
+        LTRACEF("failed to allocate 2d resource\n");
+        return err;
+    }
+
+    /* attach a backing store to the resource */
+    size_t len = gdev->pmode.r.width * gdev->pmode.r.height * 4;
+    gdev->fb = pmm_alloc_kpages(ROUNDUP(len, PAGE_SIZE) / PAGE_SIZE, NULL);
+    if (!gdev->fb) {
+        TRACEF("failed to allocate framebuffer, wanted 0x%zx bytes\n", len);
+        return ERR_NO_MEMORY;
+    }
+
+    printf("virtio-gpu: framebuffer at %p, 0x%zx bytes\n", gdev->fb, len);
+
+    err = attach_backing(gdev, gdev->display_resource_id, gdev->fb, len);
+    if (err < 0) {
+        LTRACEF("failed to attach backing store\n");
+        return err;
+    }
+
+    /* attach this resource as a scanout */
+    err = set_scanout(gdev, gdev->pmode_id, gdev->display_resource_id, gdev->pmode.r.width, gdev->pmode.r.height);
+    if (err < 0) {
+        LTRACEF("failed to set scanout\n");
+        return err;
+    }
+
+    /* create the flush thread */
+    thread_t *t;
+    t = thread_create("virtio gpu flusher", &virtio_gpu_flush_thread, (void *)gdev, HIGH_PRIORITY, DEFAULT_STACK_SIZE);
+    thread_detach_and_resume(t);
+
+    /* kick it once */
+    event_signal(&gdev->flush_event, true);
+
+    LTRACE_EXIT;
+
+    return NO_ERROR;
+}
+
+
+static void dump_gpu_config(const volatile struct virtio_gpu_config *config)
+{
+    LTRACEF("events_read 0x%x\n", config->events_read);
+    LTRACEF("events_clear 0x%x\n", config->events_clear);
+    LTRACEF("num_scanouts 0x%x\n", config->num_scanouts);
+    LTRACEF("reserved 0x%x\n", config->reserved);
+}
+
+status_t virtio_gpu_init(struct virtio_device *dev, uint32_t host_features)
+{
+    LTRACEF("dev %p, host_features 0x%x\n", dev, host_features);
+
+    /* allocate a new gpu device */
+    struct virtio_gpu_dev *gdev = malloc(sizeof(struct virtio_gpu_dev));
+    if (!gdev)
+        return ERR_NO_MEMORY;
+
+    mutex_init(&gdev->lock);
+    event_init(&gdev->io_event, false, EVENT_FLAG_AUTOUNSIGNAL);
+    event_init(&gdev->flush_event, false, EVENT_FLAG_AUTOUNSIGNAL);
+
+    gdev->dev = dev;
+    dev->priv = gdev;
+
+    gdev->pmode_id = -1;
+    gdev->next_resource_id = 1;
+
+    /* allocate memory for a gpu request */
+#if WITH_KERNEL_VM
+    gdev->gpu_request = pmm_alloc_kpage();
+    gdev->gpu_request_phys = kvaddr_to_paddr(gdev->gpu_request);
+#else
+    gdev->gpu_request = malloc(sizeof(struct virtio_gpu_resp_display_info)); // XXX get size better
+    gdev->gpu_request_phys = (paddr_t)gdev->gpu_request;
+#endif
+
+    /* make sure the device is reset */
+    virtio_reset_device(dev);
+
+    volatile struct virtio_gpu_config *config = (struct virtio_gpu_config *)dev->config_ptr;
+    dump_gpu_config(config);
+
+    /* ack and set the driver status bit */
+    virtio_status_acknowledge_driver(dev);
+
+    // XXX check features bits and ack/nak them
+
+    /* allocate a virtio ring */
+    virtio_alloc_ring(dev, 0, 16);
+
+    /* set our irq handler */
+    dev->irq_driver_callback = &virtio_gpu_irq_driver_callback;
+    dev->config_change_callback = &virtio_gpu_config_change_callback;
+
+    /* set DRIVER_OK */
+    virtio_status_driver_ok(dev);
+
+    /* save the main device we've found */
+    the_gdev = gdev;
+
+    printf("found virtio gpu device\n");
+
+    return NO_ERROR;
+}
+
+static enum handler_return virtio_gpu_irq_driver_callback(struct virtio_device *dev, uint ring, const struct vring_used_elem *e)
+{
+    struct virtio_gpu_dev *gdev = (struct virtio_gpu_dev *)dev->priv;
+
+    LTRACEF("dev %p, ring %u, e %p, id %u, len %u\n", dev, ring, e, e->id, e->len);
+
+    /* parse our descriptor chain, add back to the free queue */
+    uint16_t i = e->id;
+    for (;;) {
+        int next;
+        struct vring_desc *desc = virtio_desc_index_to_desc(dev, ring, i);
+
+        //virtio_dump_desc(desc);
+
+        if (desc->flags & VRING_DESC_F_NEXT) {
+            next = desc->next;
+        } else {
+            /* end of chain */
+            next = -1;
+        }
+
+        virtio_free_desc(dev, ring, i);
+
+        if (next < 0)
+            break;
+        i = next;
+    }
+
+    /* signal our event */
+    event_signal(&gdev->io_event, false);
+
+    return INT_RESCHEDULE;
+}
+
+static enum handler_return virtio_gpu_config_change_callback(struct virtio_device *dev)
+{
+    struct virtio_gpu_dev *gdev = (struct virtio_gpu_dev *)dev->priv;
+
+    LTRACEF("gdev %p\n", gdev);
+
+    volatile struct virtio_gpu_config *config = (struct virtio_gpu_config *)dev->config_ptr;
+    dump_gpu_config(config);
+
+    return INT_RESCHEDULE;
+}
+
+static int virtio_gpu_flush_thread(void *arg)
+{
+    struct virtio_gpu_dev *gdev = (struct virtio_gpu_dev *)arg;
+    status_t err;
+
+    for (;;) {
+        event_wait(&gdev->flush_event);
+
+        /* transfer to host 2d */
+        err = transfer_to_host_2d(gdev, gdev->display_resource_id, gdev->pmode.r.width, gdev->pmode.r.height);
+        if (err < 0) {
+            LTRACEF("failed to flush resource\n");
+            continue;
+        }
+
+        /* resource flush */
+        err = flush_resource(gdev, gdev->display_resource_id, gdev->pmode.r.width, gdev->pmode.r.height);
+        if (err < 0) {
+            LTRACEF("failed to flush resource\n");
+            continue;
+        }
+    }
+
+    return 0;
+}
+
+void virtio_gpu_gfx_flush(uint starty, uint endy)
+{
+    event_signal(&the_gdev->flush_event, !arch_ints_disabled());
+}
+
+status_t display_get_info(struct display_info *info)
+{
+    memset(info, 0, sizeof(*info));
+
+    if (!the_gdev)
+        return ERR_NOT_FOUND;
+
+    info->framebuffer = the_gdev->fb;
+    info->format = GFX_FORMAT_RGB_x888;
+    info->width = the_gdev->pmode.r.width;
+    info->height = the_gdev->pmode.r.height;
+    info->stride = info->width;
+    info->flush = virtio_gpu_gfx_flush;
+
+    return NO_ERROR;
+}
+
+
diff --git a/src/bsp/lk/dev/virtio/gpu/virtio_gpu.h b/src/bsp/lk/dev/virtio/gpu/virtio_gpu.h
new file mode 100644
index 0000000..19ed6d2
--- /dev/null
+++ b/src/bsp/lk/dev/virtio/gpu/virtio_gpu.h
@@ -0,0 +1,208 @@
+/*
+ * Virtio GPU Device
+ *
+ * Copyright Red Hat, Inc. 2013-2014
+ *
+ * Authors:
+ *     Dave Airlie <airlied@redhat.com>
+ *     Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * 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.
+ */
+
+/* taken from qemu sources */
+
+#ifndef VIRTIO_GPU_HW_H
+#define VIRTIO_GPU_HW_H
+
+#include <stdint.h>
+
+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,
+
+    /* 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,
+
+    /* 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,
+};
+
+#define VIRTIO_GPU_FLAG_FENCE (1 << 0)
+
+struct virtio_gpu_ctrl_hdr {
+    uint32_t type;
+    uint32_t flags;
+    uint64_t fence_id;
+    uint32_t ctx_id;
+    uint32_t padding;
+};
+
+/* data passed in the cursor vq */
+
+struct virtio_gpu_cursor_pos {
+    uint32_t scanout_id;
+    uint32_t x;
+    uint32_t y;
+    uint32_t 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 */
+    uint32_t resource_id;           /* update only */
+    uint32_t hot_x;                 /* update only */
+    uint32_t hot_y;                 /* update only */
+    uint32_t padding;
+};
+
+/* data passed in the control vq, 2d related */
+
+struct virtio_gpu_rect {
+    uint32_t x;
+    uint32_t y;
+    uint32_t width;
+    uint32_t height;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_UNREF */
+struct virtio_gpu_resource_unref {
+    struct virtio_gpu_ctrl_hdr hdr;
+    uint32_t resource_id;
+    uint32_t 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;
+    uint32_t resource_id;
+    uint32_t format;
+    uint32_t width;
+    uint32_t height;
+};
+
+/* VIRTIO_GPU_CMD_SET_SCANOUT */
+struct virtio_gpu_set_scanout {
+    struct virtio_gpu_ctrl_hdr hdr;
+    struct virtio_gpu_rect r;
+    uint32_t scanout_id;
+    uint32_t resource_id;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_FLUSH */
+struct virtio_gpu_resource_flush {
+    struct virtio_gpu_ctrl_hdr hdr;
+    struct virtio_gpu_rect r;
+    uint32_t resource_id;
+    uint32_t 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;
+    uint64_t offset;
+    uint32_t resource_id;
+    uint32_t padding;
+};
+
+struct virtio_gpu_mem_entry {
+    uint64_t addr;
+    uint32_t length;
+    uint32_t padding;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING */
+struct virtio_gpu_resource_attach_backing {
+    struct virtio_gpu_ctrl_hdr hdr;
+    uint32_t resource_id;
+    uint32_t nr_entries;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING */
+struct virtio_gpu_resource_detach_backing {
+    struct virtio_gpu_ctrl_hdr hdr;
+    uint32_t resource_id;
+    uint32_t 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;
+        uint32_t enabled;
+        uint32_t flags;
+    } pmodes[VIRTIO_GPU_MAX_SCANOUTS];
+};
+
+#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0)
+
+struct virtio_gpu_config {
+    uint32_t events_read;
+    uint32_t events_clear;
+    uint32_t num_scanouts;
+    uint32_t reserved;
+};
+
+/* 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,
+};
+
+#endif