diff options
| author | Camus Wong <camusw@codeaurora.org> | 2017-08-14 16:51:07 -0400 |
|---|---|---|
| committer | Camus Wong <camusw@codeaurora.org> | 2017-12-13 12:37:20 -0500 |
| commit | 822f9b4e0b428e90eea8ecdecee9012f5821628d (patch) | |
| tree | bdddec6b0fbeae474f1d0ab24722279081ed6194 /drivers/gpu | |
| parent | aaf4841e27b932dec6fae2703fae284627f335fb (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/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/Makefile | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm-hyp/Kconfig | 15 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm-hyp/Makefile | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm-hyp/NOTES | 8 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm-hyp/msm_drv_hyp.c | 257 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm-hyp/msm_drv_hyp.h | 81 |
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__ */ |
