summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Chew <achew@nvidia.com>2012-08-20 13:02:04 -0700
committerWinnie Hsu <whsu@nvidia.com>2012-12-17 11:30:58 -0800
commit62c2aed60372c97eebda02e8833c15b418a16fb0 (patch)
tree208b9f91d8b4a6a0fdf4d3599b821a83d1361c8b
parent792af1fd4fd216852b51266ccdef8f770648e922 (diff)
media: tegra: Tegra videobuf2
This is based off of videobuf2-dma-contig, except we use Tegra's nvmap for the buffer allocations. Signed-off-by: Andrew Chew <achew@nvidia.com> Change-Id: I15e689c33ee7b4fc0aade794c78701c82483df3f Reviewed-on: http://git-master/r/145345 (cherry picked from commit 70a4f20fbdd6c2c719400d6c59ef58d845657031) Signed-off-by: Bryan Wu <pengw@nvidia.com> Change-Id: Ia0632d7fcb28415e33fbb22c48f29117d7436f1d Reviewed-on: http://git-master/r/170824 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Andrew Chew <achew@nvidia.com> GVS: Gerrit_Virtual_Submit Reviewed-by: Winnie Hsu <whsu@nvidia.com>
-rw-r--r--drivers/media/video/Kconfig6
-rw-r--r--drivers/media/video/Makefile1
-rw-r--r--drivers/media/video/videobuf2-dma-nvmap.c238
-rw-r--r--include/media/videobuf2-dma-nvmap.h36
4 files changed, 281 insertions, 0 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 18c9805a8140..1d392bf0d521 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -66,6 +66,12 @@ config VIDEOBUF2_DMA_SG
select VIDEOBUF2_CORE
select VIDEOBUF2_MEMOPS
tristate
+
+config VIDEOBUF2_DMA_NVMAP
+ select VIDEOBUF2_CORE
+ select VIDEOBUF2_MEMOPS
+ tristate
+
#
# Multimedia Video device configuration
#
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 21ec2c37da23..b8663f00366e 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -122,6 +122,7 @@ obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o
obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o
obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o
obj-$(CONFIG_VIDEOBUF2_DMA_SG) += videobuf2-dma-sg.o
+obj-$(CONFIG_VIDEOBUF2_DMA_NVMAP) += videobuf2-dma-nvmap.o
obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
diff --git a/drivers/media/video/videobuf2-dma-nvmap.c b/drivers/media/video/videobuf2-dma-nvmap.c
new file mode 100644
index 000000000000..27f43e5a3a57
--- /dev/null
+++ b/drivers/media/video/videobuf2-dma-nvmap.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/>.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/nvmap.h>
+
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-memops.h>
+
+struct vb2_dc_conf {
+ struct device *dev;
+ struct nvmap_client *nvmap_client;
+};
+
+struct vb2_dc_buf {
+ struct vb2_dc_conf *conf;
+ void *vaddr;
+ dma_addr_t paddr;
+ unsigned long size;
+ struct vm_area_struct *vma;
+ atomic_t refcount;
+ struct vb2_vmarea_handler handler;
+
+ struct nvmap_handle_ref *nvmap_ref;
+};
+
+static void vb2_dma_nvmap_put(void *buf_priv);
+
+static void *vb2_dma_nvmap_alloc(void *alloc_ctx, unsigned long size)
+{
+ struct vb2_dc_conf *conf = alloc_ctx;
+ struct vb2_dc_buf *buf;
+ int ret;
+
+ buf = kzalloc(sizeof *buf, GFP_KERNEL);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ buf->nvmap_ref = nvmap_alloc(conf->nvmap_client, size, 32,
+ NVMAP_HANDLE_CACHEABLE, NVMAP_HEAP_SYSMEM);
+ if (IS_ERR(buf->nvmap_ref)) {
+ dev_err(conf->dev, "nvmap_alloc failed\n");
+ ret = -ENOMEM;
+ goto exit_free;
+ }
+
+ buf->paddr = nvmap_pin(conf->nvmap_client, buf->nvmap_ref);
+ if (IS_ERR_VALUE(buf->paddr)) {
+ dev_err(conf->dev, "nvmap_pin failed\n");
+ ret = -ENOMEM;
+ goto exit_dealloc;
+ }
+
+ buf->vaddr = nvmap_mmap(buf->nvmap_ref);
+ if (!buf->vaddr) {
+ dev_err(conf->dev, "nvmap_mmap failed\n");
+ ret = -ENOMEM;
+ goto exit_unpin;
+ }
+
+ buf->conf = conf;
+ buf->size = size;
+
+ buf->handler.refcount = &buf->refcount;
+ buf->handler.put = vb2_dma_nvmap_put;
+ buf->handler.arg = buf;
+
+ atomic_inc(&buf->refcount);
+
+ return buf;
+
+exit_unpin:
+ nvmap_unpin(conf->nvmap_client, buf->nvmap_ref);
+exit_dealloc:
+ nvmap_free(conf->nvmap_client, buf->nvmap_ref);
+exit_free:
+ kfree(buf);
+exit:
+ return ERR_PTR(ret);
+}
+
+static void vb2_dma_nvmap_put(void *buf_priv)
+{
+ struct vb2_dc_buf *buf = buf_priv;
+
+ if (atomic_dec_and_test(&buf->refcount)) {
+ nvmap_munmap(buf->nvmap_ref, buf->vaddr);
+ nvmap_unpin(buf->conf->nvmap_client, buf->nvmap_ref);
+ nvmap_free(buf->conf->nvmap_client, buf->nvmap_ref);
+ kfree(buf);
+ }
+}
+
+static void *vb2_dma_nvmap_cookie(void *buf_priv)
+{
+ struct vb2_dc_buf *buf = buf_priv;
+
+ return &buf->paddr;
+}
+
+static void *vb2_dma_nvmap_vaddr(void *buf_priv)
+{
+ struct vb2_dc_buf *buf = buf_priv;
+ if (!buf)
+ return 0;
+
+ return buf->vaddr;
+}
+
+static unsigned int vb2_dma_nvmap_num_users(void *buf_priv)
+{
+ struct vb2_dc_buf *buf = buf_priv;
+
+ return atomic_read(&buf->refcount);
+}
+
+static int vb2_dma_nvmap_mmap(void *buf_priv, struct vm_area_struct *vma)
+{
+ struct vb2_dc_buf *buf = buf_priv;
+
+ if (!buf) {
+ printk(KERN_ERR "No buffer to map\n");
+ return -EINVAL;
+ }
+
+ return vb2_mmap_pfn_range(vma, buf->paddr, buf->size,
+ &vb2_common_vm_ops, &buf->handler);
+}
+
+static void *vb2_dma_nvmap_get_userptr(void *alloc_ctx, unsigned long vaddr,
+ unsigned long size, int write)
+{
+ struct vb2_dc_buf *buf;
+ struct vm_area_struct *vma;
+ dma_addr_t paddr = 0;
+ int ret;
+
+ buf = kzalloc(sizeof *buf, GFP_KERNEL);
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+
+ ret = vb2_get_contig_userptr(vaddr, size, &vma, &paddr);
+ if (ret) {
+ printk(KERN_ERR "Failed acquiring VMA for vaddr 0x%08lx\n",
+ vaddr);
+ kfree(buf);
+ return ERR_PTR(ret);
+ }
+
+ buf->size = size;
+ buf->paddr = paddr;
+ buf->vma = vma;
+
+ return buf;
+}
+
+static void vb2_dma_nvmap_put_userptr(void *mem_priv)
+{
+ struct vb2_dc_buf *buf = mem_priv;
+
+ if (!buf)
+ return;
+
+ vb2_put_vma(buf->vma);
+ kfree(buf);
+}
+
+const struct vb2_mem_ops vb2_dma_nvmap_memops = {
+ .alloc = vb2_dma_nvmap_alloc,
+ .put = vb2_dma_nvmap_put,
+ .cookie = vb2_dma_nvmap_cookie,
+ .vaddr = vb2_dma_nvmap_vaddr,
+ .mmap = vb2_dma_nvmap_mmap,
+ .get_userptr = vb2_dma_nvmap_get_userptr,
+ .put_userptr = vb2_dma_nvmap_put_userptr,
+ .num_users = vb2_dma_nvmap_num_users,
+};
+EXPORT_SYMBOL_GPL(vb2_dma_nvmap_memops);
+
+void *vb2_dma_nvmap_init_ctx(struct device *dev)
+{
+ struct vb2_dc_conf *conf;
+ int ret;
+
+ conf = kzalloc(sizeof *conf, GFP_KERNEL);
+ if (!conf) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ conf->dev = dev;
+
+ conf->nvmap_client = nvmap_create_client(nvmap_dev,
+ "videobuf2-dma-nvmap");
+ if (!conf->nvmap_client) {
+ ret = -ENOMEM;
+ goto exit_free;
+ }
+
+ return conf;
+
+exit_free:
+ kfree(conf);
+exit:
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(vb2_dma_nvmap_init_ctx);
+
+void vb2_dma_nvmap_cleanup_ctx(void *alloc_ctx)
+{
+ struct vb2_dc_conf *conf = alloc_ctx;
+
+ nvmap_client_put(conf->nvmap_client);
+
+ kfree(alloc_ctx);
+}
+EXPORT_SYMBOL_GPL(vb2_dma_nvmap_cleanup_ctx);
+
+MODULE_DESCRIPTION("DMA-nvmap memory handling routines for videobuf2");
+MODULE_AUTHOR("Andrew Chew <achew@nvidia.com>");
+MODULE_LICENSE("GPL");
diff --git a/include/media/videobuf2-dma-nvmap.h b/include/media/videobuf2-dma-nvmap.h
new file mode 100644
index 000000000000..39ae3d3a1d5d
--- /dev/null
+++ b/include/media/videobuf2-dma-nvmap.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 _MEDIA_VIDEOBUF2_DMA_NVMAP_H
+#define _MEDIA_VIDEOBUF2_DMA_NVMAP_H
+
+#include <media/videobuf2-core.h>
+#include <linux/dma-mapping.h>
+
+static inline dma_addr_t
+vb2_dma_nvmap_plane_paddr(struct vb2_buffer *vb, unsigned int plane_no)
+{
+ dma_addr_t *paddr = vb2_plane_cookie(vb, plane_no);
+
+ return *paddr;
+}
+
+void *vb2_dma_nvmap_init_ctx(struct device *dev);
+void vb2_dma_nvmap_cleanup_ctx(void *alloc_ctx);
+
+extern const struct vb2_mem_ops vb2_dma_nvmap_memops;
+
+#endif