AMLOGIC ION device
M: Simon Zheng <simon.zheng@amlogic.com>
F: drivers/amlogic/media/common/ion_dev/*
+F: include/linux/meson_ion.h
AMLOGIC multimedia osd & ge2d
M: Pengcheng Chen <pengcheng.chen@amlogic.com>
F: sound/soc/codecs/amlogic/pdm_dummy.c
F: sound/soc/codecs/amlogic/tlv320adc3101.c
+DRM DRIVERS FOR AMLOGIC SOCS
+M: Neil Armstrong <narmstrong@baylibre.com>
+L: dri-devel@lists.freedesktop.org
+L: linux-amlogic@lists.infradead.org
+W: http://linux-meson.com/
+S: Supported
+F: drivers/amlogic/drm/
+F: Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt
+F: Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt
+T: git git://anongit.freedesktop.org/drm/drm-misc
source "drivers/amlogic/iio/Kconfig"
source "drivers/amlogic/ddr_window/Kconfig"
+
+source "drivers/amlogic/drm/Kconfig"
+
endmenu
endif
obj-$(CONFIG_AMLOGIC_IIO) += iio/
obj-$(AMLOGIC_DDR_WINDOW_TOOL) += ddr_window/
+
+obj-$(CONFIG_DRM_MESON) += drm/
--- /dev/null
+meson-y := meson_drv.o meson_gem.o meson_dmabuf.o
+#meson-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o meson_plane.o meson_crtc.o meson_venc_cvbs.o
+
+obj-$(CONFIG_DRM_MESON) += meson.o
+ccflags-y += -Idrivers/staging/android/
--- /dev/null
+/*
+ * drivers/amlogic/drm/meson_dmabuf.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ */
+
+#include <drm/drmP.h>
+#include <linux/dma-buf.h>
+#include <ion/ion.h>
+
+#include "meson_gem.h"
+#include "meson_dmabuf.h"
+
+struct dma_buf *meson_dmabuf_prime_export(struct drm_device *drm_dev,
+ struct drm_gem_object *obj, int flags)
+{
+ struct meson_gem_object *meson_gem_obj;
+ struct ion_handle *handle;
+
+ meson_gem_obj = container_of(obj, struct meson_gem_object, base);
+ handle = meson_gem_obj->handle;
+
+ if (!handle)
+ return ERR_PTR(-EINVAL);
+
+ return ion_share_dma_buf(handle->client, handle);
+}
+
+struct drm_gem_object *meson_dmabuf_prime_import(struct drm_device *drm_dev,
+ struct dma_buf *dma_buf)
+{
+ struct dma_buf_attachment *attach;
+ struct sg_table *sgt;
+ struct meson_gem_object *meson_gem_obj;
+ int ret;
+
+ attach = dma_buf_attach(dma_buf, drm_dev->dev);
+ if (IS_ERR(attach))
+ return ERR_PTR(-EINVAL);
+
+ get_dma_buf(dma_buf);
+
+ sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+ if (IS_ERR_OR_NULL(sgt)) {
+ ret = PTR_ERR(sgt);
+ goto err_buf_detach;
+ }
+
+ meson_gem_obj = meson_drm_gem_init(drm_dev, dma_buf->size);
+ if (!meson_gem_obj) {
+ ret = -ENOMEM;
+ goto err_unmap_attach;
+ }
+
+ meson_gem_obj->sgt = sgt;
+ meson_gem_obj->base.import_attach = attach;
+
+ return &meson_gem_obj->base;
+
+err_unmap_attach:
+ dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
+err_buf_detach:
+ dma_buf_detach(dma_buf, attach);
+ dma_buf_put(dma_buf);
+
+ return ERR_PTR(ret);
+}
--- /dev/null
+/*
+ * drivers/amlogic/drm/meson_dmabuf.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _MESON_DRM_DMABUF_H_
+#define _MESON_DRM_DMABUF_H_
+
+struct dma_buf *meson_dmabuf_prime_export(struct drm_device *drm_dev,
+ struct drm_gem_object *obj, int flags);
+
+struct drm_gem_object *meson_dmabuf_prime_import(struct drm_device *drm_dev,
+ struct dma_buf *dma_buf);
+
+#endif /* MESON_DRM_DMABUF_H */
#include <linux/of_graph.h>
#include <drm/drmP.h>
+
+/* #define MUSE */
+#ifdef MUSE
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_flip_work.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_plane_helper.h>
+#endif
+
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_rect.h>
#include "meson_venc.h"
#include "meson_canvas.h"
#include "meson_registers.h"
+#include "meson_gem.h"
+#include "meson_dmabuf.h"
#define DRIVER_NAME "meson"
#define DRIVER_DESC "Amlogic Meson DRM driver"
* - Powering Up HDMI controller and PHY
*/
+#ifdef MUSE
static void meson_fb_output_poll_changed(struct drm_device *dev)
{
struct meson_drm *priv = dev->dev_private;
drm_fbdev_cma_hotplug_event(priv->fbdev);
}
-
static const struct drm_mode_config_funcs meson_mode_config_funcs = {
.output_poll_changed = meson_fb_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
return IRQ_HANDLED;
}
+#endif
static const struct file_operations fops = {
.owner = THIS_MODULE,
};
static struct drm_driver meson_driver = {
+ .driver_features = DRIVER_GEM | DRIVER_PRIME,
+
+#ifdef MUSE
.driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM |
DRIVER_MODESET | DRIVER_PRIME |
DRIVER_ATOMIC,
/* IRQ */
.irq_handler = meson_irq,
+#endif
/* PRIME Ops */
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
- .gem_prime_import = drm_gem_prime_import,
- .gem_prime_export = drm_gem_prime_export,
- .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
- .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
- .gem_prime_vmap = drm_gem_cma_prime_vmap,
- .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
- .gem_prime_mmap = drm_gem_cma_prime_mmap,
+ .gem_prime_import = meson_dmabuf_prime_import,
+ .gem_prime_export = meson_dmabuf_prime_export,
/* GEM Ops */
- .dumb_create = drm_gem_cma_dumb_create,
- .dumb_destroy = drm_gem_dumb_destroy,
- .dumb_map_offset = drm_gem_cma_dumb_map_offset,
- .gem_free_object_unlocked = drm_gem_cma_free_object,
- .gem_vm_ops = &drm_gem_cma_vm_ops,
+ .open = meson_drm_gem_open,
+ .postclose = meson_drm_gem_close,
+ .dumb_create = meson_drm_gem_dumb_create,
+ .dumb_destroy = meson_drm_gem_dumb_destroy,
+ .dumb_map_offset = meson_drm_gem_dumb_map_offset,
+ .gem_free_object = meson_drm_gem_free_object,
+ .gem_vm_ops = &drm_gem_cma_vm_ops,
/* Misc */
.fops = &fops,
.minor = 0,
};
+#ifdef MUSE
static bool meson_vpu_has_available_connectors(struct device *dev)
{
struct device_node *ep, *remote;
.reg_stride = 4,
.max_register = 0x1000,
};
+#endif
static int meson_drv_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct meson_drm *priv;
struct drm_device *drm;
+ int ret;
+
+#ifdef MUSE
struct resource *res;
void __iomem *regs;
- int ret;
/* Checks if an output connector is available */
if (!meson_vpu_has_available_connectors(dev)) {
dev_err(dev, "No output connector available\n");
return -ENODEV;
}
+#endif
drm = drm_dev_alloc(&meson_driver, dev);
if (IS_ERR(drm))
priv->drm = drm;
priv->dev = dev;
+#ifdef MUSE
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpu");
regs = devm_ioremap_resource(dev, res);
if (IS_ERR(regs))
}
drm_kms_helper_poll_init(drm);
+#endif
platform_set_drvdata(pdev, priv);
return 0;
free_drm:
+ DRM_DEBUG("free-drm");
+
+#ifdef MUSE
drm_dev_unref(drm);
+#endif
return ret;
}
static int meson_drv_remove(struct platform_device *pdev)
{
struct drm_device *drm = dev_get_drvdata(&pdev->dev);
+#ifdef MUSE
struct meson_drm *priv = drm->dev_private;
+#endif
drm_dev_unregister(drm);
+#ifdef MUSE
drm_kms_helper_poll_fini(drm);
drm_fbdev_cma_fini(priv->fbdev);
drm_mode_config_cleanup(drm);
drm_vblank_cleanup(drm);
drm_dev_unref(drm);
+#endif
return 0;
}
--- /dev/null
+/*
+ * drivers/amlogic/drm/meson_gem.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_vma_manager.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <ion/ion.h>
+#include <linux/meson_ion.h>
+
+#include "meson_drv.h"
+#include "meson_gem.h"
+
+
+struct meson_gem_object *meson_drm_gem_init(struct drm_device *dev,
+ unsigned long size)
+{
+ struct meson_gem_object *meson_gem_obj;
+ struct drm_gem_object *obj;
+ int ret;
+
+ meson_gem_obj = kzalloc(sizeof(*meson_gem_obj), GFP_KERNEL);
+ if (!meson_gem_obj)
+ return NULL;
+
+ meson_gem_obj->size = size;
+ obj = &meson_gem_obj->base;
+
+ ret = drm_gem_object_init(dev, obj, size);
+ if (ret < 0) {
+ DRM_ERROR("failed to initialize gem object\n");
+ kfree(meson_gem_obj);
+ return NULL;
+ }
+
+ DRM_DEBUG("created file object = 0x%lx\n", (unsigned long)obj->filp);
+
+ return meson_gem_obj;
+}
+
+static int meson_drm_alloc_buf(struct ion_client *client,
+ struct meson_gem_object *meson_gem_obj, int flags)
+{
+ if (!client)
+ return -EINVAL;
+
+ if (!meson_gem_obj)
+ return -EINVAL;
+
+ meson_gem_obj->handle = ion_alloc(client,
+ meson_gem_obj->size,
+ 0,
+ (1 << ION_HEAP_TYPE_SYSTEM),
+ 0);
+
+ if (!meson_gem_obj->handle)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static struct meson_gem_object *meson_drm_gem_create(struct drm_device *dev,
+ unsigned int flags,
+ unsigned long size,
+ struct ion_client *client)
+{
+ struct meson_gem_object *meson_gem_obj;
+ int ret;
+
+ if (!size) {
+ DRM_ERROR("invalid size.\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ size = round_up(size, PAGE_SIZE);
+ meson_gem_obj = meson_drm_gem_init(dev, size);
+ if (!meson_gem_obj) {
+ ret = -ENOMEM;
+ return ERR_PTR(ret);
+ }
+
+ ret = meson_drm_alloc_buf(client, meson_gem_obj, flags);
+ if (ret < 0)
+ goto err_gem_fini;
+
+ return meson_gem_obj;
+
+err_gem_fini:
+ drm_gem_object_release(&meson_gem_obj->base);
+ kfree(meson_gem_obj);
+ return ERR_PTR(ret);
+}
+
+static int meson_drm_gem_handle_create(struct drm_gem_object *obj,
+ struct drm_file *file_priv,
+ unsigned int *handle)
+{
+ int ret;
+
+ /*
+ * allocate a id of idr table where the obj is registered
+ * and handle has the id what user can see.
+ */
+ ret = drm_gem_handle_create(file_priv, obj, handle);
+ if (ret)
+ return ret;
+
+ DRM_DEBUG("gem handle = 0x%x\n", *handle);
+
+ /* drop reference from allocate - handle holds it now. */
+ drm_gem_object_unreference_unlocked(obj);
+
+ return 0;
+}
+
+static void meson_drm_free_buf(struct drm_device *dev,
+ struct meson_gem_object *meson_gem_obj)
+{
+ struct ion_client *client = NULL;
+
+ if (meson_gem_obj->handle) {
+ client = meson_gem_obj->handle->client;
+ ion_free(client, meson_gem_obj->handle);
+ } else {
+ DRM_ERROR("meson_gem_obj handle is null\n");
+ }
+}
+
+void meson_drm_gem_destroy(struct meson_gem_object *meson_gem_obj)
+{
+ struct drm_gem_object *obj;
+
+ obj = &meson_gem_obj->base;
+
+ DRM_DEBUG("handle count = %d\n", obj->handle_count);
+
+ /*
+ * do not release memory region from exporter.
+ *
+ * the region will be released by exporter
+ * once dmabuf's refcount becomes 0.
+ */
+ if (obj->import_attach)
+ goto out;
+
+ meson_drm_free_buf(obj->dev, meson_gem_obj);
+
+out:
+
+ drm_gem_free_mmap_offset(obj);
+
+ /* release file pointer to gem object. */
+ drm_gem_object_release(obj);
+
+ kfree(meson_gem_obj);
+ meson_gem_obj = NULL;
+}
+
+int meson_drm_gem_dumb_create(struct drm_file *file_priv,
+ struct drm_device *dev, struct drm_mode_create_dumb *args)
+{
+ int ret = 0;
+ struct meson_gem_object *meson_gem_obj;
+ struct drm_meson_file_private *f = file_priv->driver_priv;
+
+ struct ion_client *client = (struct ion_client *) f->client;
+ int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+
+ args->pitch = ALIGN(min_pitch, 64);
+ if (args->size < args->pitch * args->height)
+ args->size = args->pitch * args->height;
+
+ meson_gem_obj = meson_drm_gem_create(dev, 0, args->size, client);
+
+ if (IS_ERR(meson_gem_obj))
+ return PTR_ERR(meson_gem_obj);
+
+ ret = meson_drm_gem_handle_create(&meson_gem_obj->base, file_priv,
+ &args->handle);
+ if (ret) {
+ meson_drm_gem_destroy(meson_gem_obj);
+ return ret;
+ }
+
+ return 0;
+}
+
+int meson_drm_gem_dumb_map_offset(struct drm_file *file_priv,
+ struct drm_device *dev, uint32_t handle,
+ uint64_t *offset)
+{
+ struct drm_gem_object *obj;
+ int ret = 0;
+
+ mutex_lock(&dev->struct_mutex);
+
+ /*
+ * get offset of memory allocated for drm framebuffer.
+ * - this callback would be called by user application
+ * with DRM_IOCTL_MODE_MAP_DUMB command.
+ */
+
+ obj = drm_gem_object_lookup(file_priv, handle);
+ if (!obj) {
+ DRM_ERROR("failed to lookup gem object.\n");
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ ret = drm_gem_create_mmap_offset(obj);
+ if (ret)
+ goto out;
+
+ *offset = drm_vma_node_offset_addr(&obj->vma_node);
+ DRM_DEBUG("offset = 0x%lx\n", (unsigned long)*offset);
+
+out:
+ drm_gem_object_unreference(obj);
+unlock:
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+}
+
+void meson_drm_gem_free_object(struct drm_gem_object *obj)
+{
+ struct meson_gem_object *meson_gem_obj;
+
+ meson_gem_obj = container_of(obj, struct meson_gem_object, base);
+
+ if (obj->import_attach)
+ drm_prime_gem_destroy(obj, meson_gem_obj->sgt);
+
+ meson_drm_gem_destroy(meson_gem_obj);
+}
+
+int meson_drm_gem_dumb_destroy(struct drm_file *file,
+ struct drm_device *dev,
+ uint32_t handle)
+{
+ struct drm_gem_object *obj;
+
+ spin_lock(&file->table_lock);
+ obj = idr_find(&file->object_idr, handle);
+ if (obj == NULL) {
+ spin_unlock(&file->table_lock);
+ return -EINVAL;
+ }
+ spin_unlock(&file->table_lock);
+
+ drm_gem_handle_delete(file, handle);
+
+ /*
+ * we still have a reference to dma_buf because the ion_handle,
+ * when gem obj handle count become zero and refcount is 1.
+ * It will not release when dma_buf_ops.release is called.
+ * we have to drop it here.
+ * drop the reference on the export fd holds
+ */
+
+ if (obj->handle_count == 0 &&
+ atomic_read(&obj->refcount.refcount) == 1)
+ drm_gem_object_unreference_unlocked(obj);
+
+ return 0;
+}
+
+int meson_drm_gem_open(struct drm_device *dev, struct drm_file *file)
+{
+ struct drm_meson_file_private *file_priv;
+
+ file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
+ if (!file_priv) {
+ DRM_ERROR("drm_meson file private alloc fail\n");
+ return -ENOMEM;
+ }
+
+ file_priv->client = meson_ion_client_create(-1, "meson-gem");
+ if (!file_priv->client) {
+ DRM_ERROR("open ion client error\n");
+ return -EFAULT;
+ }
+
+ DRM_DEBUG("open ion client: %p\n", file_priv->client);
+ file->driver_priv = (void *) file_priv;
+ return 0;
+}
+
+void meson_drm_gem_close(struct drm_device *dev, struct drm_file *file)
+{
+ struct drm_meson_file_private *file_priv = file->driver_priv;
+ struct ion_client *gem_ion_client = file_priv->client;
+
+ if (gem_ion_client) {
+ DRM_DEBUG(" destroy ion client: %p\n", gem_ion_client);
+ ion_client_destroy(gem_ion_client);
+ }
+}
--- /dev/null
+/*
+ * drivers/amlogic/drm/meson_gem.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __MESON_GEM_H
+#define __MESON_GEM_H
+#include <drm/drm_gem.h>
+#include <ion/ion_priv.h>
+
+struct drm_meson_file_private {
+ struct ion_client *client;
+};
+
+struct meson_gem_object {
+ struct drm_gem_object base;
+ struct ion_handle *handle;
+ struct sg_table *sgt;
+ unsigned long size;
+ unsigned int flags;
+};
+
+/* create memory region for drm */
+int meson_drm_gem_dumb_create(struct drm_file *file_priv,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args);
+
+/* map memory region for drm to user space. */
+int meson_drm_gem_dumb_map_offset(struct drm_file *file_priv,
+ struct drm_device *dev, uint32_t handle,
+ uint64_t *offset);
+
+/* free gem object. */
+void meson_drm_gem_free_object(struct drm_gem_object *gem_obj);
+
+struct meson_gem_object *meson_drm_gem_init(struct drm_device *dev,
+ unsigned long size);
+
+int meson_drm_gem_dumb_destroy(struct drm_file *file,
+ struct drm_device *dev,
+ uint32_t handle);
+
+int meson_drm_gem_open(struct drm_device *dev, struct drm_file *file);
+void meson_drm_gem_close(struct drm_device *dev, struct drm_file *file);
+
+#endif /* __MESON_GEM_H */
source "drivers/gpu/drm/mediatek/Kconfig"
-source "drivers/gpu/drm/meson/Kconfig"
-
# Keep legacy drivers last
menuconfig DRM_LEGACY
obj-$(CONFIG_DRM_STI) += sti/
obj-$(CONFIG_DRM_IMX) += imx/
obj-$(CONFIG_DRM_MEDIATEK) += mediatek/
-obj-$(CONFIG_DRM_MESON) += meson/
obj-y += i2c/
obj-y += panel/
obj-y += bridge/
+++ /dev/null
-meson-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o
-meson-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o
-
-obj-$(CONFIG_DRM_MESON) += meson.o
--- /dev/null
+#include "../../drivers/amlogic/media/common/ion_dev/meson_ion.h"