summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
authorCamus Wong <camusw@codeaurora.org>2017-08-14 16:51:07 -0400
committerCamus Wong <camusw@codeaurora.org>2017-12-13 12:37:20 -0500
commit822f9b4e0b428e90eea8ecdecee9012f5821628d (patch)
treebdddec6b0fbeae474f1d0ab24722279081ed6194 /drivers/gpu
parentaaf4841e27b932dec6fae2703fae284627f335fb (diff)
drm/msm-hyp: new virtual msm driver
This driver is enabled on hypervisor builds for the purpose of creating a DRM device that DRM Master can open and listen on for VBlank and Page Flip events. Change-Id: Ib9b2df5ae0e2c33145663b3f515595e8f433a850 Signed-off-by: Camus Wong <camusw@codeaurora.org>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/Kconfig2
-rw-r--r--drivers/gpu/drm/Makefile1
-rw-r--r--drivers/gpu/drm/msm-hyp/Kconfig15
-rw-r--r--drivers/gpu/drm/msm-hyp/Makefile4
-rw-r--r--drivers/gpu/drm/msm-hyp/NOTES8
-rw-r--r--drivers/gpu/drm/msm-hyp/msm_drv_hyp.c257
-rw-r--r--drivers/gpu/drm/msm-hyp/msm_drv_hyp.h81
7 files changed, 368 insertions, 0 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index f4554b39d5d9..021d8391abea 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -267,3 +267,5 @@ source "drivers/gpu/drm/amd/amdkfd/Kconfig"
source "drivers/gpu/drm/imx/Kconfig"
source "drivers/gpu/drm/vc4/Kconfig"
+
+source "drivers/gpu/drm/msm-hyp/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 1e9ff4c3e3db..ea0d5ea57213 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -68,6 +68,7 @@ obj-$(CONFIG_DRM_QXL) += qxl/
obj-$(CONFIG_DRM_BOCHS) += bochs/
obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio/
obj-$(CONFIG_DRM_MSM) += msm/
+obj-$(CONFIG_DRM_MSM_HYP) += msm-hyp/
obj-$(CONFIG_DRM_TEGRA) += tegra/
obj-$(CONFIG_DRM_STI) += sti/
obj-$(CONFIG_DRM_IMX) += imx/
diff --git a/drivers/gpu/drm/msm-hyp/Kconfig b/drivers/gpu/drm/msm-hyp/Kconfig
new file mode 100644
index 000000000000..676c0174c0ee
--- /dev/null
+++ b/drivers/gpu/drm/msm-hyp/Kconfig
@@ -0,0 +1,15 @@
+#
+# Drm MSM hypervisor configuration
+#
+# This driver provides support for the User Space DRM Masters
+#
+config DRM_MSM_HYP
+ tristate "MSM DRM HYP"
+ depends on DRM
+ depends on MSM_GVM_QUIN
+ depends on OF
+ default y
+ help
+ DRM/KMS driver for MSM/snapdragon in Guest VM mode. This driver registers
+ with DRM framework to create /dev/dri/card0 path and issue events to User
+ Space listeners.
diff --git a/drivers/gpu/drm/msm-hyp/Makefile b/drivers/gpu/drm/msm-hyp/Makefile
new file mode 100644
index 000000000000..dbf54f0e58c7
--- /dev/null
+++ b/drivers/gpu/drm/msm-hyp/Makefile
@@ -0,0 +1,4 @@
+ccflags-y := -Iinclude/drm
+
+obj-y := \
+ msm_drv_hyp.o
diff --git a/drivers/gpu/drm/msm-hyp/NOTES b/drivers/gpu/drm/msm-hyp/NOTES
new file mode 100644
index 000000000000..9571da75b604
--- /dev/null
+++ b/drivers/gpu/drm/msm-hyp/NOTES
@@ -0,0 +1,8 @@
+NOTES about msm drm/kms hyp driver:
+
+This driver registers with drm framework for the purpose of creating the
+/dev/dri/card0 path, which User Space DRM Masters rely on.
+Furthermore, per-CRTC VBLANK and PAGE_FLIP events are queued to the device
+path to notify User Space components listeners.
+
+No other IOCTL or HW support is provided through this driver. \ No newline at end of file
diff --git a/drivers/gpu/drm/msm-hyp/msm_drv_hyp.c b/drivers/gpu/drm/msm-hyp/msm_drv_hyp.c
new file mode 100644
index 000000000000..7dd817e41ddd
--- /dev/null
+++ b/drivers/gpu/drm/msm-hyp/msm_drv_hyp.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ *
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * Copyright (C) 2014 Red Hat
+ * Copyright (C) 2014 Intel Corp.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors:
+ * Rob Clark <robdclark@gmail.com>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+#include "msm_drv_hyp.h"
+
+/*
+ * DRM operations:
+ */
+
+static int msm_unload(struct drm_device *dev)
+{
+ struct msm_drm_private *priv = dev->dev_private;
+
+ dev->dev_private = NULL;
+
+ kfree(priv);
+
+ return 0;
+}
+
+static int msm_load(struct drm_device *dev, unsigned long flags)
+{
+ struct msm_drm_private *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev->dev_private = priv;
+
+ return 0;
+}
+
+static int msm_open(struct drm_device *dev, struct drm_file *file)
+{
+ struct msm_file_private *ctx;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ file->driver_priv = ctx;
+
+ return 0;
+}
+
+static void msm_preclose(struct drm_device *dev, struct drm_file *file)
+{
+ struct msm_drm_private *priv = dev->dev_private;
+ struct msm_file_private *ctx = file->driver_priv;
+
+ mutex_lock(&dev->struct_mutex);
+ if (ctx == priv->lastctx)
+ priv->lastctx = NULL;
+ mutex_unlock(&dev->struct_mutex);
+
+ kfree(ctx);
+}
+
+static struct drm_pending_vblank_event *create_vblank_event(
+ struct drm_device *dev, struct drm_file *file_priv, u32 type,
+ uint64_t user_data)
+{
+ struct drm_pending_vblank_event *e = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ if (file_priv->event_space < sizeof(e->event)) {
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ goto out;
+ }
+ file_priv->event_space -= sizeof(e->event);
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ e = kzalloc(sizeof(*e), GFP_KERNEL);
+ if (e == NULL) {
+ spin_lock_irqsave(&dev->event_lock, flags);
+ file_priv->event_space += sizeof(e->event);
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ goto out;
+ }
+
+ e->event.base.type = type;
+ e->event.base.length = sizeof(e->event);
+ e->event.user_data = user_data;
+ e->base.event = &e->event.base;
+ e->base.file_priv = file_priv;
+ e->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
+
+out:
+ return e;
+}
+
+struct event_req {
+ u32 type;
+ u64 user_data;
+};
+
+static size_t msm_drm_write(struct file *filp, const char __user *buffer,
+ size_t count, loff_t *offset)
+{
+ struct drm_file *file_priv = filp->private_data;
+ struct drm_device *dev = file_priv->minor->dev;
+ struct event_req e_req;
+ struct drm_pending_vblank_event *e;
+ unsigned long flags;
+ int ret = 0;
+
+ if (count != sizeof(struct event_req))
+ return -EINVAL;
+
+ if (!access_ok(VERIFY_READ, buffer, count))
+ return -EFAULT;
+
+ ret = copy_from_user(&e_req, buffer, sizeof(e_req));
+ if (ret)
+ return -EFAULT;
+
+ if (!(e_req.type & DRM_EVENT_VBLANK) &&
+ !(e_req.type & DRM_EVENT_FLIP_COMPLETE))
+ return -EINVAL;
+
+ e = create_vblank_event(dev, file_priv, e_req.type, e_req.user_data);
+ if (!e)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ drm_send_vblank_event(dev, 2, e);
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ return count;
+}
+
+static const struct file_operations fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = drm_ioctl,
+ .poll = drm_poll,
+ .read = drm_read,
+ .write = msm_drm_write,
+ .llseek = no_llseek,
+};
+
+static struct drm_driver msm_driver = {
+ .driver_features = 0,
+ .load = msm_load,
+ .unload = msm_unload,
+ .open = msm_open,
+ .preclose = msm_preclose,
+ .set_busid = drm_platform_set_busid,
+ .get_vblank_counter = drm_vblank_no_hw_counter,
+ .num_ioctls = 0,
+ .fops = &fops,
+ .name = "msm_drm_hyp",
+ .desc = "MSM Snapdragon DRM",
+ .date = "20170831",
+ .major = 1,
+ .minor = 0,
+};
+
+/*
+ * Platform driver:
+ */
+
+static int msm_pdev_probe(struct platform_device *pdev)
+{
+ return drm_platform_init(&msm_driver, pdev);
+}
+
+static int msm_pdev_remove(struct platform_device *pdev)
+{
+ drm_put_dev(platform_get_drvdata(pdev));
+
+ return 0;
+}
+
+static const struct platform_device_id msm_id[] = {
+ { "mdp-hyp", 0 },
+ { }
+};
+
+static const struct of_device_id dt_match[] = {
+ { .compatible = "qcom,sde-kms-hyp" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, dt_match);
+
+static struct platform_driver msm_platform_driver = {
+ .probe = msm_pdev_probe,
+ .remove = msm_pdev_remove,
+ .driver = {
+ .name = "msm_drm_hyp",
+ .of_match_table = dt_match,
+ },
+ .id_table = msm_id,
+};
+
+static int __init msm_drm_register(void)
+{
+ DBG("init");
+ return platform_driver_register(&msm_platform_driver);
+}
+
+static void __exit msm_drm_unregister(void)
+{
+ DBG("fini");
+ platform_driver_unregister(&msm_platform_driver);
+}
+
+module_init(msm_drm_register);
+module_exit(msm_drm_unregister);
+
+MODULE_DESCRIPTION("MSM DRM Mini Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/msm-hyp/msm_drv_hyp.h b/drivers/gpu/drm/msm-hyp/msm_drv_hyp.h
new file mode 100644
index 000000000000..affce322ba06
--- /dev/null
+++ b/drivers/gpu/drm/msm-hyp/msm_drv_hyp.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ *
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MSM_DRV_HYP_H__
+#define __MSM_DRV_HYP_H__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/sizes.h>
+#include <linux/kthread.h>
+
+#include <drm/drmP.h>
+
+struct msm_file_private {
+ /* currently we don't do anything useful with this.. but when
+ * per-context address spaces are supported we'd keep track of
+ * the context's page-tables here.
+ */
+ int dummy;
+};
+
+enum msm_mdp_display_id {
+ DISPLAY_ID_NONE,
+ DISPLAY_ID_PRIMARY,
+ DISPLAY_ID_SECONDARY,
+ DISPLAY_ID_TERTIARY,
+ DISPLAY_ID_QUATERNARY,
+ DISPLAY_ID_MAX
+};
+
+struct msm_drm_private {
+ struct msm_file_private *lastctx;
+};
+
+#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
+#define VERB(fmt, ...) (if (0) DRM_DEBUG(fmt"\n", ##__VA_ARGS__))
+
+static inline enum msm_mdp_display_id msm_get_display_id(
+ const char *display_type)
+{
+ if (!display_type)
+ return DISPLAY_ID_NONE;
+ else if (!strcmp(display_type, "primary"))
+ return DISPLAY_ID_PRIMARY;
+ else if (!strcmp(display_type, "secondary"))
+ return DISPLAY_ID_SECONDARY;
+ else if (!strcmp(display_type, "tertiary"))
+ return DISPLAY_ID_TERTIARY;
+ else if (!strcmp(display_type, "quaternary"))
+ return DISPLAY_ID_QUATERNARY;
+ else
+ return DISPLAY_ID_NONE;
+};
+
+/* for the generated headers: */
+#define FIELD(val, name) (((val) & name ## __MASK) >> name ## __SHIFT)
+
+/* for conditionally setting boolean flag(s): */
+#define COND(bool, val) ((bool) ? (val) : 0)
+
+#endif /* __MSM_DRV_HYP_H__ */