From 7580bf0377d1cde114b73e9758f311d7e237b26e Mon Sep 17 00:00:00 2001 From: Pengcheng Chen Date: Thu, 3 Jan 2019 15:50:50 +0800 Subject: [PATCH] ge2d: add ge2d dma_buf support [1/2] PD#SWPL-4036 Problem: don't support dma_buf Solution: add ge2d dma_buf support Verify: test pass on w400 Change-Id: I1277d04fb30753e579d5edc5f46f2406dc27217a Signed-off-by: Pengcheng Chen --- MAINTAINERS | 7 +- drivers/amlogic/media/common/ge2d/Makefile | 3 +- drivers/amlogic/media/common/ge2d/ge2d_dmabuf.c | 634 +++++++++++++++++++ drivers/amlogic/media/common/ge2d/ge2d_dmabuf.h | 81 +++ drivers/amlogic/media/common/ge2d/ge2d_main.c | 261 ++++++++ drivers/amlogic/media/common/ge2d/ge2d_wq.c | 805 +++++++++++++++++++++--- drivers/amlogic/media/common/ge2d/ge2d_wq.h | 5 + include/linux/amlogic/media/ge2d/ge2d.h | 80 +++ 8 files changed, 1790 insertions(+), 86 deletions(-) create mode 100644 drivers/amlogic/media/common/ge2d/ge2d_dmabuf.c create mode 100644 drivers/amlogic/media/common/ge2d/ge2d_dmabuf.h diff --git a/MAINTAINERS b/MAINTAINERS index 2e5e232..2ad404f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14765,4 +14765,9 @@ F: drivers/amlogic/media/Makefile F: drivers/amlogic/media/camera/* F: drivers/amlogic/media/common/canvas/canvas_mgr.c F: drivers/amlogic/media/common/vfm/vfm.c -F: include/linux/amlogic/media/camera/* \ No newline at end of file +F: include/linux/amlogic/media/camera/* + +AMLOGIC multimedia +M: Pengcheng Chen +F: drivers/amlogic/media/common/ge2d/ge2d_dmabuf.c +F: drivers/amlogic/media/common/ge2d/ge2d_dmabuf.h \ No newline at end of file diff --git a/drivers/amlogic/media/common/ge2d/Makefile b/drivers/amlogic/media/common/ge2d/Makefile index 666b3f3..c5ad763 100644 --- a/drivers/amlogic/media/common/ge2d/Makefile +++ b/drivers/amlogic/media/common/ge2d/Makefile @@ -5,7 +5,8 @@ ge2d-objs = bitblt.o \ ge2d_wq.o \ stretchblt.o \ ge2d_main.o \ - blend.o + blend.o \ + ge2d_dmabuf.o obj-$(CONFIG_AMLOGIC_MEDIA_GE2D) += ge2d.o ccflags-y += -Iinclude/linux/media/ge2d/ diff --git a/drivers/amlogic/media/common/ge2d/ge2d_dmabuf.c b/drivers/amlogic/media/common/ge2d/ge2d_dmabuf.c new file mode 100644 index 0000000..e5d6b65 --- /dev/null +++ b/drivers/amlogic/media/common/ge2d/ge2d_dmabuf.c @@ -0,0 +1,634 @@ +/* + * drivers/amlogic/media/common/ge2d/ge2d_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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ge2d_log.h" +#include "ge2d_dmabuf.h" + +/* dma free*/ +static void aml_dma_put(void *buf_priv) +{ + struct aml_dma_buf *buf = buf_priv; + + if (!atomic_dec_and_test(&buf->refcount)) { + ge2d_log_dbg("aml_dma_put, refcont=%d\n", + atomic_read(&buf->refcount)); + return; + } + if (buf->sgt_base) { + sg_free_table(buf->sgt_base); + kfree(buf->sgt_base); + } + dma_free_attrs(buf->dev, buf->size, buf->cookie, buf->dma_addr, + buf->attrs); + put_device(buf->dev); + kfree(buf); + ge2d_log_dbg("aml_dma_put free!\n"); +} + +static void *aml_dma_alloc(struct device *dev, unsigned long attrs, + unsigned long size, enum dma_data_direction dma_dir, + gfp_t gfp_flags) +{ + struct aml_dma_buf *buf; + + if (WARN_ON(!dev)) + return (void *)(-EINVAL); + + buf = kzalloc(sizeof(struct aml_dma_buf), GFP_KERNEL); + if (!buf) + return NULL; + + if (attrs) + buf->attrs = attrs; + buf->cookie = dma_alloc_attrs(dev, size, &buf->dma_addr, + gfp_flags, buf->attrs); + if (!buf->cookie) { + dev_err(dev, "dma_alloc_coherent of size %ld failed\n", size); + kfree(buf); + return NULL; + } + + if ((buf->attrs & DMA_ATTR_NO_KERNEL_MAPPING) == 0) + buf->vaddr = buf->cookie; + + /* Prevent the device from being released while the buffer is used */ + buf->dev = get_device(dev); + buf->size = size; + buf->dma_dir = dma_dir; + + atomic_inc(&buf->refcount); + ge2d_log_dbg("aml_dma_alloc, refcont=%d\n", + atomic_read(&buf->refcount)); + + return buf; +} + +static int aml_dma_mmap(void *buf_priv, struct vm_area_struct *vma) +{ + struct aml_dma_buf *buf = buf_priv; + int ret; + + if (!buf) { + pr_err("No buffer to map\n"); + return -EINVAL; + } + + /* + * dma_mmap_* uses vm_pgoff as in-buffer offset, but we want to + * map whole buffer + */ + vma->vm_pgoff = 0; + + ret = dma_mmap_attrs(buf->dev, vma, buf->cookie, + buf->dma_addr, buf->size, buf->attrs); + + if (ret) { + pr_err("Remapping memory failed, error: %d\n", ret); + return ret; + } + ge2d_log_dbg("mapped dma addr 0x%08lx at 0x%08lx, size %d\n", + (unsigned long)buf->dma_addr, vma->vm_start, + buf->size); + return 0; +} + +/*********************************************/ +/* DMABUF ops for exporters */ +/*********************************************/ +struct aml_attachment { + struct sg_table sgt; + enum dma_data_direction dma_dir; +}; + +static int aml_dmabuf_ops_attach(struct dma_buf *dbuf, struct device *dev, + struct dma_buf_attachment *dbuf_attach) +{ + struct aml_attachment *attach; + unsigned int i; + struct scatterlist *rd, *wr; + struct sg_table *sgt; + struct aml_dma_buf *buf = dbuf->priv; + int ret; + + attach = kzalloc(sizeof(*attach), GFP_KERNEL); + if (!attach) + return -ENOMEM; + + sgt = &attach->sgt; + /* Copy the buf->base_sgt scatter list to the attachment, as we can't + * map the same scatter list to multiple attachments at the same time. + */ + ret = sg_alloc_table(sgt, buf->sgt_base->orig_nents, GFP_KERNEL); + if (ret) { + kfree(attach); + return -ENOMEM; + } + + rd = buf->sgt_base->sgl; + wr = sgt->sgl; + for (i = 0; i < sgt->orig_nents; ++i) { + sg_set_page(wr, sg_page(rd), rd->length, rd->offset); + rd = sg_next(rd); + wr = sg_next(wr); + } + + attach->dma_dir = DMA_NONE; + dbuf_attach->priv = attach; + + return 0; +} + +static void aml_dmabuf_ops_detach(struct dma_buf *dbuf, + struct dma_buf_attachment *db_attach) +{ + struct aml_attachment *attach = db_attach->priv; + struct sg_table *sgt; + + if (!attach) + return; + + sgt = &attach->sgt; + + /* release the scatterlist cache */ + if (attach->dma_dir != DMA_NONE) + dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, + attach->dma_dir); + sg_free_table(sgt); + kfree(attach); + db_attach->priv = NULL; + +} + +static struct sg_table *aml_dmabuf_ops_map( + struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir) +{ + struct aml_attachment *attach = db_attach->priv; + /* stealing dmabuf mutex to serialize map/unmap operations */ + struct mutex *lock = &db_attach->dmabuf->lock; + struct sg_table *sgt; + + mutex_lock(lock); + + sgt = &attach->sgt; + /* return previously mapped sg table */ + if (attach->dma_dir == dma_dir) { + mutex_unlock(lock); + return sgt; + } + + /* release any previous cache */ + if (attach->dma_dir != DMA_NONE) { + dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, + attach->dma_dir); + attach->dma_dir = DMA_NONE; + } + + /* mapping to the client with new direction */ + sgt->nents = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, + dma_dir); + if (!sgt->nents) { + pr_err("failed to map scatterlist\n"); + mutex_unlock(lock); + return (void *)(-EIO); + } + + attach->dma_dir = dma_dir; + + mutex_unlock(lock); + return sgt; +} + +static void aml_dmabuf_ops_unmap(struct dma_buf_attachment *db_attach, + struct sg_table *sgt, enum dma_data_direction dma_dir) +{ + /* nothing to be done here */ +} + +static void aml_dmabuf_ops_release(struct dma_buf *dbuf) +{ + /* drop reference obtained in vb2_dc_get_dmabuf */ + aml_dma_put(dbuf->priv); +} + +static void *aml_dmabuf_ops_kmap(struct dma_buf *dbuf, unsigned long pgnum) +{ + struct aml_dma_buf *buf = dbuf->priv; + + return buf->vaddr ? buf->vaddr + pgnum * PAGE_SIZE : NULL; +} + +static void *aml_dmabuf_ops_vmap(struct dma_buf *dbuf) +{ + struct aml_dma_buf *buf = dbuf->priv; + + return buf->vaddr; +} + +static int aml_dmabuf_ops_mmap(struct dma_buf *dbuf, + struct vm_area_struct *vma) +{ + return aml_dma_mmap(dbuf->priv, vma); +} + +static struct dma_buf_ops ge2d_dmabuf_ops = { + .attach = aml_dmabuf_ops_attach, + .detach = aml_dmabuf_ops_detach, + .map_dma_buf = aml_dmabuf_ops_map, + .unmap_dma_buf = aml_dmabuf_ops_unmap, + .kmap = aml_dmabuf_ops_kmap, + .kmap_atomic = aml_dmabuf_ops_kmap, + .vmap = aml_dmabuf_ops_vmap, + .mmap = aml_dmabuf_ops_mmap, + .release = aml_dmabuf_ops_release, +}; + +static struct sg_table *get_base_sgt(struct aml_dma_buf *buf) +{ + int ret; + struct sg_table *sgt; + + sgt = kmalloc(sizeof(struct sg_table), GFP_KERNEL); + if (!sgt) + return NULL; + + ret = dma_get_sgtable(buf->dev, sgt, buf->cookie, + buf->dma_addr, buf->size); + if (ret < 0) { + dev_err(buf->dev, "failed to get scatterlist from DMA API\n"); + kfree(sgt); + return NULL; + } + return sgt; +} + +static struct dma_buf *get_dmabuf(void *buf_priv, unsigned long flags) +{ + struct aml_dma_buf *buf = buf_priv; + struct dma_buf *dbuf; + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + + exp_info.ops = &ge2d_dmabuf_ops; + exp_info.size = buf->size; + exp_info.flags = flags; + exp_info.priv = buf; + + if (!buf->sgt_base) + buf->sgt_base = get_base_sgt(buf); + + if (WARN_ON(!buf->sgt_base)) + return NULL; + + dbuf = dma_buf_export(&exp_info); + if (IS_ERR(dbuf)) + return NULL; + + /* dmabuf keeps reference to vb2 buffer */ + atomic_inc(&buf->refcount); + ge2d_log_dbg("get_dmabuf, refcount=%d\n", + atomic_read(&buf->refcount)); + return dbuf; +} + +/* ge2d dma-buf api.h*/ +static int find_empty_dma_buffer(struct aml_dma_buffer *buffer) +{ + int i; + int found = 0; + + for (i = 0; i < AML_MAX_DMABUF; i++) { + if (buffer->gd_buffer[i].alloc) + continue; + else { + ge2d_log_dbg("find_empty_dma_buffer i=%d\n", i); + found = 1; + break; + } + } + if (found) + return i; + else + return -1; +} + +void *ge2d_dma_buffer_create(void) +{ + int i; + struct aml_dma_buffer *buffer; + + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) + return NULL; + + mutex_init(&buffer->lock); + for (i = 0; i < AML_MAX_DMABUF; i++) { + buffer->gd_buffer[i].mem_priv = NULL; + buffer->gd_buffer[i].index = 0; + buffer->gd_buffer[i].alloc = 0; + } + return buffer; +} + +void ge2d_dma_buffer_destroy(struct aml_dma_buffer *buffer) +{ + kfree(buffer); +} + +int ge2d_dma_buffer_alloc(struct aml_dma_buffer *buffer, + struct device *dev, + struct ge2d_dmabuf_req_s *ge2d_req_buf) +{ + void *buf; + unsigned int size; + int index; + + if (WARN_ON(!dev)) + return (-EINVAL); + if (!ge2d_req_buf) + return (-EINVAL); + if (!buffer) + return (-EINVAL); + + size = PAGE_ALIGN(ge2d_req_buf->len); + if (size == 0) + return (-EINVAL); + + index = find_empty_dma_buffer(buffer); + if ((index < 0) || (index >= AML_MAX_DMABUF)) { + pr_err("no empty buffer found\n"); + return (-ENOMEM); + } + + buf = aml_dma_alloc(dev, 0, size, ge2d_req_buf->dma_dir, + GFP_HIGHUSER | __GFP_ZERO); + if (!buf) + return (-ENOMEM); + + mutex_lock(&(buffer->lock)); + buffer->gd_buffer[index].mem_priv = buf; + buffer->gd_buffer[index].index = index; + buffer->gd_buffer[index].alloc = 1; + mutex_unlock(&(buffer->lock)); + ge2d_req_buf->index = index; + return 0; +} + +int ge2d_dma_buffer_free(struct aml_dma_buffer *buffer, int index) +{ + struct aml_dma_buf *buf; + + if (!buffer) + return (-EINVAL); + if ((index < 0) || (index >= AML_MAX_DMABUF)) + return (-EINVAL); + + buf = buffer->gd_buffer[index].mem_priv; + if (!buf) { + pr_err("aml_dma_buf is null\n"); + return (-EINVAL); + } + aml_dma_put(buf); + return 0; +} + +int ge2d_dma_buffer_export(struct aml_dma_buffer *buffer, + struct ge2d_dmabuf_exp_s *ge2d_exp_buf) +{ + struct aml_dma_buf *buf; + struct dma_buf *dbuf; + int ret, index; + unsigned int flags; + + if (!ge2d_exp_buf) + return (-EINVAL); + if (!buffer) + return (-EINVAL); + + index = ge2d_exp_buf->index; + if ((index < 0) || (index >= AML_MAX_DMABUF)) + return (-EINVAL); + + flags = ge2d_exp_buf->flags; + buf = buffer->gd_buffer[index].mem_priv; + if (!buf) { + pr_err("aml_dma_buf is null\n"); + return (-EINVAL); + } + + dbuf = get_dmabuf(buf, flags & O_ACCMODE); + if (IS_ERR_OR_NULL(dbuf)) { + pr_err("failed to export buffer %d\n", index); + return -EINVAL; + } + ret = dma_buf_fd(dbuf, flags & ~O_ACCMODE); + if (ret < 0) { + pr_err("buffer %d, failed to export (%d)\n", + index, ret); + dma_buf_put(dbuf); + return ret; + } + + ge2d_log_dbg("buffer %d,exported as %d descriptor\n", + index, ret); + ge2d_exp_buf->fd = ret; + return 0; +} + +int ge2d_dma_buffer_map(struct aml_dma_cfg *cfg) +{ + long ret = -1; + int fd = -1; + struct dma_buf *dbuf = NULL; + struct dma_buf_attachment *d_att = NULL; + struct sg_table *sg = NULL; + void *vaddr = NULL; + struct device *dev = NULL; + enum dma_data_direction dir; + + if (cfg == NULL || (cfg->fd < 0) || cfg->dev == NULL) { + pr_err("error input param"); + return -EINVAL; + } + fd = cfg->fd; + dev = cfg->dev; + dir = cfg->dir; + + dbuf = dma_buf_get(fd); + if (dbuf == NULL) { + pr_err("failed to get dma buffer"); + return -EINVAL; + } + + d_att = dma_buf_attach(dbuf, dev); + if (d_att == NULL) { + pr_err("failed to set dma attach"); + goto attach_err; + } + + sg = dma_buf_map_attachment(d_att, dir); + if (sg == NULL) { + pr_err("failed to get dma sg"); + goto map_attach_err; + } + + ret = dma_buf_begin_cpu_access(dbuf, dir); + if (ret != 0) { + pr_err("failed to access dma buff"); + goto access_err; + } + + vaddr = dma_buf_vmap(dbuf); + if (vaddr == NULL) { + pr_err("failed to vmap dma buf"); + goto vmap_err; + } + cfg->dbuf = dbuf; + cfg->attach = d_att; + cfg->vaddr = vaddr; + cfg->sg = sg; + return ret; + +vmap_err: + dma_buf_end_cpu_access(dbuf, dir); + +access_err: + dma_buf_unmap_attachment(d_att, sg, dir); + +map_attach_err: + dma_buf_detach(dbuf, d_att); + +attach_err: + dma_buf_put(dbuf); + + return ret; +} + +int ge2d_dma_buffer_get_phys(struct aml_dma_cfg *cfg, unsigned long *addr) +{ + struct sg_table *sg_table; + struct page *page; + int ret; + + ret = ge2d_dma_buffer_map(cfg); + if (ret < 0) { + pr_err("gdc_dma_buffer_map failed\n"); + return ret; + } + if (cfg->sg) { + sg_table = cfg->sg; + page = sg_page(sg_table->sgl); + *addr = PFN_PHYS(page_to_pfn(page)); + ret = 0; + } + ge2d_dma_buffer_unmap(cfg); + return ret; +} + +void ge2d_dma_buffer_unmap(struct aml_dma_cfg *cfg) +{ + int fd = -1; + struct dma_buf *dbuf = NULL; + struct dma_buf_attachment *d_att = NULL; + struct sg_table *sg = NULL; + void *vaddr = NULL; + struct device *dev = NULL; + enum dma_data_direction dir; + + if (cfg == NULL || (cfg->fd < 0) || cfg->dev == NULL + || cfg->dbuf == NULL || cfg->vaddr == NULL + || cfg->attach == NULL || cfg->sg == NULL) { + pr_err("Error input param"); + return; + } + fd = cfg->fd; + dev = cfg->dev; + dir = cfg->dir; + dbuf = cfg->dbuf; + vaddr = cfg->vaddr; + d_att = cfg->attach; + sg = cfg->sg; + + dma_buf_vunmap(dbuf, vaddr); + + dma_buf_end_cpu_access(dbuf, dir); + + dma_buf_unmap_attachment(d_att, sg, dir); + + dma_buf_detach(dbuf, d_att); + + dma_buf_put(dbuf); +} + +void ge2d_dma_buffer_dma_flush(struct device *dev, int fd) +{ + struct dma_buf *dmabuf; + struct aml_dma_buf *buf; + + ge2d_log_dbg("ge2d_dma_buffer_dma_flush fd=%d\n", fd); + dmabuf = dma_buf_get(fd); + if (IS_ERR(dmabuf)) { + pr_err("dma_buf_get failed\n"); + return; + } + buf = dmabuf->priv; + if (!buf) { + pr_err("error input param"); + return; + } + if (buf->size > 0) + dma_sync_single_for_device(buf->dev, buf->dma_addr, + buf->size, DMA_TO_DEVICE); + dma_buf_put(dmabuf); +} + +void ge2d_dma_buffer_cache_flush(struct device *dev, int fd) +{ + struct dma_buf *dmabuf; + struct aml_dma_buf *buf; + + ge2d_log_dbg("ge2d_dma_buffer_cache_flush fd=%d\n", fd); + dmabuf = dma_buf_get(fd); + if (IS_ERR(dmabuf)) { + pr_err("dma_buf_get failed\n"); + return; + } + buf = dmabuf->priv; + if (!buf) { + pr_err("error input param"); + return; + } + if (buf->size > 0) + dma_sync_single_for_device(buf->dev, buf->dma_addr, + buf->size, DMA_FROM_DEVICE); + dma_buf_put(dmabuf); +} + + diff --git a/drivers/amlogic/media/common/ge2d/ge2d_dmabuf.h b/drivers/amlogic/media/common/ge2d/ge2d_dmabuf.h new file mode 100644 index 0000000..85dc94b --- /dev/null +++ b/drivers/amlogic/media/common/ge2d/ge2d_dmabuf.h @@ -0,0 +1,81 @@ +/* + * drivers/amlogic/media/common/ge2d/ge2d_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 _GE2D_DMABUF_H_ +#define _GE2D_DMABUF_H_ + +#include +#include +#include + +/* Amlogic Headers */ +#include + +#define AML_MAX_DMABUF 32 + +struct aml_dma_buf { + struct device *dev; + void *cookie; + void *vaddr; + unsigned int size; + enum dma_data_direction dma_dir; + unsigned long attrs; + unsigned int index; + dma_addr_t dma_addr; + atomic_t refcount; + struct sg_table *sgt_base; + /* DMABUF related */ + struct dma_buf_attachment *db_attach; +}; + +struct aml_dma_buf_priv { + void *mem_priv; + int index; + unsigned int alloc; + struct dma_buf *dbuf; +}; + +struct aml_dma_buffer { + struct mutex lock; + struct aml_dma_buf_priv gd_buffer[AML_MAX_DMABUF]; +}; + +struct aml_dma_cfg { + int fd; + void *dev; + void *vaddr; + struct dma_buf *dbuf; + struct dma_buf_attachment *attach; + struct sg_table *sg; + enum dma_data_direction dir; +}; + + +void *ge2d_dma_buffer_create(void); +void ge2d_dma_buffer_destroy(struct aml_dma_buffer *buffer); +int ge2d_dma_buffer_alloc(struct aml_dma_buffer *buffer, + struct device *dev, + struct ge2d_dmabuf_req_s *ge2d_req_buf); +int ge2d_dma_buffer_free(struct aml_dma_buffer *buffer, int index); +int ge2d_dma_buffer_export(struct aml_dma_buffer *buffer, + struct ge2d_dmabuf_exp_s *ge2d_exp_buf); +int ge2d_dma_buffer_map(struct aml_dma_cfg *cfg); +void ge2d_dma_buffer_unmap(struct aml_dma_cfg *cfg); +int ge2d_dma_buffer_get_phys(struct aml_dma_cfg *cfg, unsigned long *addr); +void ge2d_dma_buffer_dma_flush(struct device *dev, int fd); +void ge2d_dma_buffer_cache_flush(struct device *dev, int fd); +#endif diff --git a/drivers/amlogic/media/common/ge2d/ge2d_main.c b/drivers/amlogic/media/common/ge2d/ge2d_main.c index 666f675..7a768ce 100644 --- a/drivers/amlogic/media/common/ge2d/ge2d_main.c +++ b/drivers/amlogic/media/common/ge2d/ge2d_main.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_COMPAT @@ -47,6 +48,7 @@ #include "ge2dgen.h" #include "ge2d_log.h" #include "ge2d_wq.h" +#include "ge2d_dmabuf.h" #define GE2D_CLASS_NAME "ge2d" #define MAX_GE2D_CLK 500000000 @@ -210,6 +212,197 @@ static int ge2d_open(struct inode *inode, struct file *file) return 0; } +static int ge2d_ioctl_config_ex_mem(struct ge2d_context_s *context, + unsigned int cmd, unsigned long args) +{ + struct config_para_ex_memtype_s *ge2d_config_ex_mem; + struct config_ge2d_para_ex_s ge2d_para_config; + int ret = 0; +#ifdef CONFIG_COMPAT + struct compat_config_para_ex_memtype_s __user *uf_ex_mem; + struct compat_config_ge2d_para_ex_s __user *uf_ge2d_para; + int r = 0; + int i, j; +#endif + void __user *argp = (void __user *)args; + + memset(&ge2d_para_config, 0, sizeof(struct config_ge2d_para_ex_s)); + switch (cmd) { + case GE2D_CONFIG_EX_MEM: + ret = copy_from_user(&ge2d_para_config, argp, + sizeof(struct config_ge2d_para_ex_s)); + ge2d_config_ex_mem = &(ge2d_para_config.para_config_memtype); + ret = ge2d_context_config_ex_mem(context, ge2d_config_ex_mem); + break; +#ifdef CONFIG_COMPAT + case GE2D_CONFIG_EX32_MEM: + uf_ge2d_para = (struct compat_config_ge2d_para_ex_s *)argp; + r |= get_user(ge2d_para_config.para_config_memtype.ge2d_magic, + &uf_ge2d_para->para_config_memtype.ge2d_magic); + ge2d_config_ex_mem = &(ge2d_para_config.para_config_memtype); + + if (ge2d_para_config.para_config_memtype.ge2d_magic + == sizeof(struct config_para_ex_memtype_s)) { + struct config_para_ex_ion_s *pge2d_config_ex; + + uf_ex_mem = + (struct compat_config_para_ex_memtype_s *)argp; + pge2d_config_ex = + &(ge2d_config_ex_mem->_ge2d_config_ex); + r = copy_from_user( + &pge2d_config_ex->src_para, + &uf_ex_mem->_ge2d_config_ex.src_para, + sizeof(struct src_dst_para_ex_s)); + r |= copy_from_user( + &pge2d_config_ex->src2_para, + &uf_ex_mem->_ge2d_config_ex.src2_para, + sizeof(struct src_dst_para_ex_s)); + r |= copy_from_user( + &pge2d_config_ex->dst_para, + &uf_ex_mem->_ge2d_config_ex.dst_para, + sizeof(struct src_dst_para_ex_s)); + r |= copy_from_user(&pge2d_config_ex->src_key, + &uf_ex_mem->_ge2d_config_ex.src_key, + sizeof(struct src_key_ctrl_s)); + r |= copy_from_user(&pge2d_config_ex->src2_key, + &uf_ex_mem->_ge2d_config_ex.src2_key, + sizeof(struct src_key_ctrl_s)); + + r |= get_user(pge2d_config_ex->src1_cmult_asel, + &uf_ex_mem->_ge2d_config_ex.src1_cmult_asel); + r |= get_user(pge2d_config_ex->src2_cmult_asel, + &uf_ex_mem->_ge2d_config_ex.src2_cmult_asel); + r |= get_user(pge2d_config_ex->alu_const_color, + &uf_ex_mem->_ge2d_config_ex.alu_const_color); + r |= get_user(pge2d_config_ex->src1_gb_alpha_en, + &uf_ex_mem->_ge2d_config_ex.src1_gb_alpha_en); + r |= get_user(pge2d_config_ex->src1_gb_alpha, + &uf_ex_mem->_ge2d_config_ex.src1_gb_alpha); +#ifdef CONFIG_GE2D_SRC2 + r |= get_user(pge2d_config_ex->src2_gb_alpha_en, + &uf_ex_mem->_ge2d_config_ex.src2_gb_alpha_en); + r |= get_user(pge2d_config_ex->src2_gb_alpha, + &uf_ex_mem->_ge2d_config_ex.src2_gb_alpha); +#endif + r |= get_user(pge2d_config_ex->op_mode, + &uf_ex_mem->_ge2d_config_ex.op_mode); + r |= get_user(pge2d_config_ex->bitmask_en, + &uf_ex_mem->_ge2d_config_ex.bitmask_en); + r |= get_user(pge2d_config_ex->bytemask_only, + &uf_ex_mem->_ge2d_config_ex.bytemask_only); + r |= get_user(pge2d_config_ex->bitmask, + &uf_ex_mem->_ge2d_config_ex.bitmask); + r |= get_user(pge2d_config_ex->dst_xy_swap, + &uf_ex_mem->_ge2d_config_ex.dst_xy_swap); + r |= get_user(pge2d_config_ex->hf_init_phase, + &uf_ex_mem->_ge2d_config_ex.hf_init_phase); + r |= get_user(pge2d_config_ex->hf_rpt_num, + &uf_ex_mem->_ge2d_config_ex.hf_rpt_num); + r |= get_user(pge2d_config_ex->hsc_start_phase_step, + &uf_ex_mem->_ge2d_config_ex + .hsc_start_phase_step); + r |= get_user(pge2d_config_ex->hsc_phase_slope, + &uf_ex_mem->_ge2d_config_ex.hsc_phase_slope); + r |= get_user(pge2d_config_ex->vf_init_phase, + &uf_ex_mem->_ge2d_config_ex.vf_init_phase); + r |= get_user(pge2d_config_ex->vf_rpt_num, + &uf_ex_mem->_ge2d_config_ex.vf_rpt_num); + r |= get_user(pge2d_config_ex->vsc_start_phase_step, + &uf_ex_mem->_ge2d_config_ex + .vsc_start_phase_step); + r |= get_user(pge2d_config_ex->vsc_phase_slope, + &uf_ex_mem->_ge2d_config_ex.vsc_phase_slope); + r |= get_user( + pge2d_config_ex->src1_vsc_phase0_always_en, + &uf_ex_mem->_ge2d_config_ex + .src1_vsc_phase0_always_en); + r |= get_user( + pge2d_config_ex->src1_hsc_phase0_always_en, + &uf_ex_mem->_ge2d_config_ex + .src1_hsc_phase0_always_en); + r |= get_user( + pge2d_config_ex->src1_hsc_rpt_ctrl, + &uf_ex_mem->_ge2d_config_ex.src1_hsc_rpt_ctrl); + r |= get_user( + pge2d_config_ex->src1_vsc_rpt_ctrl, + &uf_ex_mem->_ge2d_config_ex.src1_vsc_rpt_ctrl); + + for (i = 0; i < 4; i++) { + struct config_planes_ion_s *psrc_planes; + + psrc_planes = + &pge2d_config_ex->src_planes[i]; + r |= get_user(psrc_planes->addr, + &uf_ex_mem->_ge2d_config_ex + .src_planes[i].addr); + r |= get_user(psrc_planes->w, + &uf_ex_mem->_ge2d_config_ex + .src_planes[i].w); + r |= get_user(psrc_planes->h, + &uf_ex_mem->_ge2d_config_ex + .src_planes[i].h); + r |= get_user(psrc_planes->shared_fd, + &uf_ex_mem->_ge2d_config_ex + .src_planes[i].shared_fd); + } + + for (i = 0; i < 4; i++) { + struct config_planes_ion_s *psrc2_planes; + + psrc2_planes = + &pge2d_config_ex->src2_planes[i]; + r |= get_user(psrc2_planes->addr, + &uf_ex_mem->_ge2d_config_ex + .src2_planes[i].addr); + r |= get_user(psrc2_planes->w, + &uf_ex_mem->_ge2d_config_ex + .src2_planes[i].w); + r |= get_user(psrc2_planes->h, + &uf_ex_mem->_ge2d_config_ex + .src2_planes[i].h); + r |= get_user(psrc2_planes->shared_fd, + &uf_ex_mem->_ge2d_config_ex + .src2_planes[i].shared_fd); + } + + for (j = 0; j < 4; j++) { + struct config_planes_ion_s *pdst_planes; + + pdst_planes = + &pge2d_config_ex->dst_planes[j]; + r |= get_user(pdst_planes->addr, + &uf_ex_mem->_ge2d_config_ex + .dst_planes[j].addr); + r |= get_user(pdst_planes->w, + &uf_ex_mem->_ge2d_config_ex + .dst_planes[j].w); + r |= get_user(pdst_planes->h, + &uf_ex_mem->_ge2d_config_ex + .dst_planes[j].h); + r |= get_user(pdst_planes->shared_fd, + &uf_ex_mem->_ge2d_config_ex + .dst_planes[j].shared_fd); + } + + r |= get_user(ge2d_config_ex_mem->src1_mem_alloc_type, + &uf_ex_mem->src1_mem_alloc_type); + r |= get_user(ge2d_config_ex_mem->src2_mem_alloc_type, + &uf_ex_mem->src2_mem_alloc_type); + r |= get_user(ge2d_config_ex_mem->dst_mem_alloc_type, + &uf_ex_mem->dst_mem_alloc_type); + + } + if (r) { + pr_err("GE2D_CONFIG_EX32 get parameter failed .\n"); + return -EFAULT; + } + ret = ge2d_context_config_ex_mem(context, ge2d_config_ex_mem); + break; +#endif + } + return ret; +} + static long ge2d_ioctl(struct file *filp, unsigned int cmd, unsigned long args) { struct ge2d_context_s *context = NULL; @@ -217,6 +410,8 @@ static long ge2d_ioctl(struct file *filp, unsigned int cmd, unsigned long args) struct ge2d_para_s para; struct config_para_ex_s ge2d_config_ex; struct config_para_ex_ion_s ge2d_config_ex_ion; + struct ge2d_dmabuf_req_s ge2d_req_buf; + struct ge2d_dmabuf_exp_s ge2d_exp_buf; int ret = 0; #ifdef CONFIG_COMPAT struct compat_config_para_s __user *uf; @@ -226,12 +421,15 @@ static long ge2d_ioctl(struct file *filp, unsigned int cmd, unsigned long args) int i, j; #endif int cap_mask = 0; + int index = 0, dma_fd; void __user *argp = (void __user *)args; context = (struct ge2d_context_s *)filp->private_data; memset(&ge2d_config, 0, sizeof(struct config_para_s)); memset(&ge2d_config_ex, 0, sizeof(struct config_para_ex_s)); memset(&ge2d_config_ex_ion, 0, sizeof(struct config_para_ex_ion_s)); + memset(&ge2d_req_buf, 0, sizeof(struct ge2d_dmabuf_req_s)); + memset(&ge2d_exp_buf, 0, sizeof(struct ge2d_dmabuf_exp_s)); #ifdef CONFIG_AMLOGIC_MEDIA_GE2D_MORE_SECURITY switch (cmd) { case GE2D_CONFIG: @@ -538,6 +736,39 @@ static long ge2d_ioctl(struct file *filp, unsigned int cmd, unsigned long args) case GE2D_SET_COEF: case GE2D_ANTIFLICKER_ENABLE: break; + case GE2D_REQUEST_BUFF: + ret = copy_from_user(&ge2d_req_buf, argp, + sizeof(struct ge2d_dmabuf_req_s)); + if (ret < 0) { + pr_err("Error user param\n"); + return -EINVAL; + } + break; + case GE2D_EXP_BUFF: + ret = copy_from_user(&ge2d_exp_buf, argp, + sizeof(struct ge2d_dmabuf_exp_s)); + if (ret < 0) { + pr_err("Error user param\n"); + return -EINVAL; + } + break; + case GE2D_FREE_BUFF: + ret = copy_from_user(&index, argp, + sizeof(int)); + if (ret < 0) { + pr_err("Error user param\n"); + return -EINVAL; + } + break; + case GE2D_SYNC_DEVICE: + case GE2D_SYNC_CPU: + ret = copy_from_user(&dma_fd, argp, + sizeof(int)); + if (ret < 0) { + pr_err("Error user param\n"); + return -EINVAL; + } + break; case GE2D_CONFIG_OLD: case GE2D_CONFIG_EX_OLD: case GE2D_SRCCOLORKEY_OLD: @@ -568,6 +799,12 @@ static long ge2d_ioctl(struct file *filp, unsigned int cmd, unsigned long args) #endif ret = ge2d_context_config_ex_ion(context, &ge2d_config_ex_ion); break; + case GE2D_CONFIG_EX_MEM: +#ifdef CONFIG_COMPAT + case GE2D_CONFIG_EX32_MEM: +#endif + ret = ge2d_ioctl_config_ex_mem(context, cmd, args); + break; case GE2D_SET_COEF: ge2d_wq_set_scale_coef(context, args & 0xff, args >> 16); break; @@ -744,6 +981,27 @@ static long ge2d_ioctl(struct file *filp, unsigned int cmd, unsigned long args) para.dst_rect.x, para.dst_rect.y, para.dst_rect.w, para.dst_rect.h); break; + case GE2D_REQUEST_BUFF: + ret = ge2d_buffer_alloc(&ge2d_req_buf); + if (ret == 0) + ret = copy_to_user(argp, &ge2d_req_buf, + sizeof(struct ge2d_dmabuf_req_s)); + break; + case GE2D_EXP_BUFF: + ret = ge2d_buffer_export(&ge2d_exp_buf); + if (ret == 0) + ret = copy_to_user(argp, &ge2d_exp_buf, + sizeof(struct ge2d_dmabuf_exp_s)); + break; + case GE2D_FREE_BUFF: + ret = ge2d_buffer_free(index); + break; + case GE2D_SYNC_DEVICE: + ge2d_buffer_dma_flush(dma_fd); + break; + case GE2D_SYNC_CPU: + ge2d_buffer_cache_flush(dma_fd); + break; } return ret; } @@ -961,6 +1219,9 @@ static int ge2d_probe(struct platform_device *pdev) (void *)res.start, (int)resource_size(&res)); } } + ret = of_reserved_mem_device_init(&(pdev->dev)); + if (ret < 0) + ge2d_log_info("reserved mem init failed\n"); ret = ge2d_wq_init(pdev, irq, clk_gate); diff --git a/drivers/amlogic/media/common/ge2d/ge2d_wq.c b/drivers/amlogic/media/common/ge2d/ge2d_wq.c index a35947d..66ce8a1 100644 --- a/drivers/amlogic/media/common/ge2d/ge2d_wq.c +++ b/drivers/amlogic/media/common/ge2d/ge2d_wq.c @@ -41,6 +41,7 @@ #include "ge2d_io.h" #include "ge2d_reg.h" #include "ge2d_wq.h" +#include "ge2d_dmabuf.h" #include "osd_io.h" #include "osd_hw.h" @@ -928,6 +929,49 @@ static int build_ge2d_addr_config_ion( return ret; } +static int build_ge2d_addr_config_dma( + struct config_planes_ion_s *plane, + unsigned int format, + unsigned int *addr, + unsigned int *stride, + unsigned int dir + ) +{ + int ret = -1; + int bpp_value = bpp(format); + unsigned long addr_temp = 0; + + bpp_value /= 8; + ge2d_log_dbg("build_ge2d_addr_config_ion bpp_value=%d\n", + bpp_value); + if (plane) { + if (plane[0].shared_fd) { + struct aml_dma_cfg cfg; + + cfg.fd = plane[0].shared_fd; + cfg.dev = &(ge2d_manager.pdev->dev); + cfg.dir = dir; + ret = ge2d_dma_buffer_get_phys(&cfg, &addr_temp); + if (ret != 0) + return ret; + } + plane[0].addr += addr_temp; + if (plane[0].addr) { + *addr = plane[0].addr; + *stride = plane[0].w * bpp_value; + ret = 0; + } + /* not support multi-src_planes */ + if ((plane[1].addr) || + (plane[2].addr) || + (plane[3].addr)) { + ge2d_log_info("ge2d not support NV21 mode\n"); + ret = -1; + } + } + return ret; +} + static int build_ge2d_config_ex(struct config_planes_s *plane, unsigned int format, unsigned int *canvas_index, @@ -1066,6 +1110,84 @@ static int build_ge2d_config_ex_ion(struct config_planes_ion_s *plane, } return ret; } +static int build_ge2d_config_ex_dma(struct config_planes_ion_s *plane, + unsigned int format, + unsigned int *canvas_index, + int index, + unsigned int *r_offset, + unsigned int dir) +{ + int bpp_value = bpp(format); + int ret = -1; + unsigned long addr; + + bpp_value /= 8; + index &= 0xff; + if (plane) { + if (plane[0].shared_fd) { + struct aml_dma_cfg cfg; + + cfg.fd = plane[0].shared_fd; + cfg.dev = &(ge2d_manager.pdev->dev); + cfg.dir = dir; + ret = ge2d_dma_buffer_get_phys(&cfg, &addr); + ge2d_log_info("phys: addr=%lx\n", addr); + if (ret != 0) + return ret; + + plane[0].addr += addr; + *canvas_index = index; + *r_offset += 1; +#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS + canvas_config(index++, plane[0].addr, + plane[0].w * bpp_value, + plane[0].h, + CANVAS_ADDR_NOWRAP, + CANVAS_BLKMODE_LINEAR); +#endif + ret = 0; + } + /* multi-src_planes */ + if (plane[1].addr) { + plane[1].addr += plane[0].addr; + *canvas_index |= index << 8; + *r_offset += 1; +#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS + canvas_config(index++, plane[1].addr, + plane[1].w * bpp_value, + plane[1].h, + CANVAS_ADDR_NOWRAP, + CANVAS_BLKMODE_LINEAR); +#endif + } + if (plane[2].addr) { + plane[2].addr += plane[0].addr; + *canvas_index |= index << 16; + *r_offset += 1; +#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS + canvas_config(index++, plane[2].addr, + plane[2].w * bpp_value, + plane[2].h, + CANVAS_ADDR_NOWRAP, + CANVAS_BLKMODE_LINEAR); +#endif + } + if (plane[3].addr) { + plane[3].addr += plane[0].addr; + *canvas_index |= index << 24; + *r_offset += 1; +#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS + canvas_config(index++, plane[3].addr, + plane[3].w * bpp_value, + plane[3].h, + CANVAS_ADDR_NOWRAP, + CANVAS_BLKMODE_LINEAR); +#endif + } + } + return ret; +} + int ge2d_context_config_ex(struct ge2d_context_s *context, struct config_para_ex_s *ge2d_config) { @@ -1814,99 +1936,609 @@ int ge2d_context_config_ex_ion(struct ge2d_context_s *context, return 0; } -struct ge2d_context_s *create_ge2d_work_queue(void) +int ge2d_context_config_ex_mem(struct ge2d_context_s *context, + struct config_para_ex_memtype_s *ge2d_config_mem) { - int i; - struct ge2d_queue_item_s *p_item; - struct ge2d_context_s *ge2d_work_queue; - int empty; - - ge2d_work_queue = kzalloc(sizeof(struct ge2d_context_s), GFP_KERNEL); - ge2d_work_queue->config.h_scale_coef_type = FILTER_TYPE_BILINEAR; - ge2d_work_queue->config.v_scale_coef_type = FILTER_TYPE_BILINEAR; - ge2d_work_queue->ge2d_request_exit = 0; - if (IS_ERR(ge2d_work_queue)) { - ge2d_log_err("can't create work queue\n"); - return NULL; - } - INIT_LIST_HEAD(&ge2d_work_queue->work_queue); - INIT_LIST_HEAD(&ge2d_work_queue->free_queue); - init_waitqueue_head(&ge2d_work_queue->cmd_complete); - spin_lock_init(&ge2d_work_queue->lock); /* for process lock. */ - for (i = 0; i < MAX_GE2D_CMD; i++) { - p_item = kcalloc(1, - sizeof(struct ge2d_queue_item_s), - GFP_KERNEL); - if (IS_ERR(p_item)) { - ge2d_log_err("can't request queue item memory\n"); - return NULL; - } - list_add_tail(&p_item->list, &ge2d_work_queue->free_queue); - } - - /* put this process queue into manager queue list. */ - /* maybe process queue is changing . */ - spin_lock(&ge2d_manager.event.sem_lock); - empty = list_empty(&ge2d_manager.process_queue); - list_add_tail(&ge2d_work_queue->list, &ge2d_manager.process_queue); - spin_unlock(&ge2d_manager.event.sem_lock); - return ge2d_work_queue; /* find it */ -} -EXPORT_SYMBOL(create_ge2d_work_queue); + struct src_dst_para_s tmp; + unsigned int index = 0; + unsigned int alloc_canvas_offset = 0; + struct ge2d_src1_gen_s *src1_gen_cfg; + struct ge2d_src2_dst_data_s *src2_dst_data_cfg; + struct ge2d_src2_dst_gen_s *src2_dst_gen_cfg; + struct ge2d_dp_gen_s *dp_gen_cfg; + struct ge2d_cmd_s *ge2d_cmd_cfg; + int top, left, width, height; + unsigned int src_addr = 0, src2_addr = 0, dst_addr = 0; + unsigned int src_stride = 0, src2_stride = 0, dst_stride = 0; + struct config_para_ex_ion_s *ge2d_config; -int destroy_ge2d_work_queue(struct ge2d_context_s *ge2d_work_queue) -{ - struct ge2d_queue_item_s *pitem, *tmp; - struct list_head *head; - int empty, timeout = 0; + ge2d_config = &(ge2d_config_mem->_ge2d_config_ex); + /* setup src and dst */ + switch (ge2d_config->src_para.mem_type) { + case CANVAS_OSD0: + case CANVAS_OSD1: + if (setup_display_property(&tmp, + (ge2d_config->src_para.mem_type == CANVAS_OSD0) ? + OSD1_CANVAS_INDEX : OSD2_CANVAS_INDEX) < 0) + return -1; + ge2d_config->src_para.canvas_index = tmp.canvas_index; + ge2d_config->src_para.format = tmp.ge2d_color_index; + src_addr = tmp.phy_addr; + src_stride = tmp.stride; - if (ge2d_work_queue) { - /* first detatch it from the process queue,then delete it . */ - /* maybe process queue is changing .so we lock it. */ - spin_lock(&ge2d_manager.event.sem_lock); - list_del(&ge2d_work_queue->list); - empty = list_empty(&ge2d_manager.process_queue); - spin_unlock(&ge2d_manager.event.sem_lock); - if ((ge2d_manager.current_wq == ge2d_work_queue) && - (ge2d_manager.ge2d_state == GE2D_STATE_RUNNING)) { - ge2d_work_queue->ge2d_request_exit = 1; - timeout = wait_for_completion_timeout( - &ge2d_manager.event.process_complete, - msecs_to_jiffies(500)); - if (!timeout) - ge2d_log_err("wait timeout\n"); - /* condition so complex ,simplify it . */ - ge2d_manager.last_wq = NULL; - } /* else we can delete it safely. */ + ge2d_log_dbg("ge2d: src1-->type: osd%d, format: 0x%x !!\n", + ge2d_config->src_para.mem_type - CANVAS_OSD0, + ge2d_config->src_para.format); - head = &ge2d_work_queue->work_queue; - list_for_each_entry_safe(pitem, tmp, head, list) { - if (pitem) { - list_del(&pitem->list); - kfree(pitem); - } + top = ge2d_config->src_para.top; + left = ge2d_config->src_para.left; + width = ge2d_config->src_para.width; + height = ge2d_config->src_para.height; + if ((left + width > tmp.xres) || + (top + height > tmp.yres)) { + ge2d_log_dbg("ge2d src error: out of range\n"); + return -1; } - head = &ge2d_work_queue->free_queue; - list_for_each_entry_safe(pitem, tmp, head, list) { - if (pitem) { - list_del(&pitem->list); - kfree(pitem); + ge2d_config->src_para.width = tmp.xres; + ge2d_config->src_para.height = tmp.yres; + ge2d_log_dbg("ge2d osd phy_addr:0x%x,stride=0x%x,format:0x%x\n", + src_addr, + src_stride, + ge2d_config->src_para.format); + break; + case CANVAS_ALLOC: + top = ge2d_config->src_para.top; + left = ge2d_config->src_para.left; + width = ge2d_config->src_para.width; + height = ge2d_config->src_para.height; + if ((left + width > ge2d_config->src_planes[0].w) + || (top + height > ge2d_config->src_planes[0].h)) { + ge2d_log_dbg("ge2d error: src alloc, out of range\n"); + return -1; + } + if (ge2d_meson_dev.canvas_status == 1) { + if (ge2d_config_mem->src1_mem_alloc_type == + AML_GE2D_MEM_ION) { + if (build_ge2d_addr_config_ion( + &ge2d_config->src_planes[0], + ge2d_config->src_para.format, + &src_addr, + &src_stride) < 0) + return -1; + ge2d_log_dbg("ge2d ion alloc phy_addr:0x%x,stride=0x%x,format:0x%x\n", + src_addr, + src_stride, + ge2d_config->src_para.format); + } else if (ge2d_config_mem->src1_mem_alloc_type == + AML_GE2D_MEM_DMABUF) { + if (build_ge2d_addr_config_dma( + &ge2d_config->src_planes[0], + ge2d_config->src_para.format, + &src_addr, + &src_stride, + DMA_TO_DEVICE) < 0) + return -1; + ge2d_log_dbg("ge2d dma alloc phy_addr:0x%x,stride=0x%x,format:0x%x\n", + src_addr, + src_stride, + ge2d_config->src_para.format); + } + } else { + if (ge2d_config_mem->src1_mem_alloc_type == + AML_GE2D_MEM_ION) { + if (build_ge2d_config_ex_ion( + &ge2d_config->src_planes[0], + ge2d_config->src_para.format, + &index, + ALLOC_CANVAS_INDEX + + alloc_canvas_offset, + &alloc_canvas_offset) < 0) + return -1; + ge2d_config->src_para.canvas_index = index; + ge2d_log_dbg("ge2d ion alloc canvas index:0x%x, format:0x%x\n", + index, ge2d_config->src_para.format); + } else if (ge2d_config_mem->src1_mem_alloc_type == + AML_GE2D_MEM_DMABUF) { + if (build_ge2d_config_ex_dma( + &ge2d_config->src_planes[0], + ge2d_config->src_para.format, + &index, + ALLOC_CANVAS_INDEX + + alloc_canvas_offset, + &alloc_canvas_offset, + DMA_TO_DEVICE) < 0) + return -1; + ge2d_config->src_para.canvas_index = index; + ge2d_log_dbg("ge2d dma alloc canvas index:0x%x, format:0x%x\n", + index, ge2d_config->src_para.format); } } - - kfree(ge2d_work_queue); - ge2d_work_queue = NULL; - return 0; + break; + default: + break; } - return -1; -} -EXPORT_SYMBOL(destroy_ge2d_work_queue); - -int ge2d_wq_init(struct platform_device *pdev, - int irq, struct clk *clk) -{ - struct ge2d_gen_s ge2d_gen_cfg; + switch (ge2d_config->src2_para.mem_type) { + case CANVAS_OSD0: + case CANVAS_OSD1: + if (setup_display_property(&tmp, + (ge2d_config->src2_para.mem_type == CANVAS_OSD0) ? + OSD1_CANVAS_INDEX : OSD2_CANVAS_INDEX) < 0) + return -1; + ge2d_config->src2_para.canvas_index = tmp.canvas_index; + ge2d_config->src2_para.format = tmp.ge2d_color_index; + src2_addr = tmp.phy_addr; + src2_stride = tmp.stride; + + ge2d_log_dbg("ge2d: src2-->type: osd%d, format: 0x%x !!\n", + ge2d_config->src2_para.mem_type - CANVAS_OSD0, + ge2d_config->src2_para.format); + + top = ge2d_config->src2_para.top; + left = ge2d_config->src2_para.left; + width = ge2d_config->src2_para.width; + height = ge2d_config->src2_para.height; + if ((left + width > tmp.xres) || (top + height > tmp.yres)) { + ge2d_log_dbg("ge2d error: src2: osd%d, out of range\n", + ge2d_config->src2_para.mem_type - CANVAS_OSD0); + return -1; + } + ge2d_config->src2_para.width = tmp.xres; + ge2d_config->src2_para.height = tmp.yres; + ge2d_log_dbg("ge2d osd phy_addr:0x%x,stride=0x%x,format:0x%x\n", + src2_addr, + src2_stride, + ge2d_config->src2_para.format); + break; + case CANVAS_ALLOC: + top = ge2d_config->src2_para.top; + left = ge2d_config->src2_para.left; + width = ge2d_config->src2_para.width; + height = ge2d_config->src2_para.height; + if ((left + width > ge2d_config->src2_planes[0].w) + || (top + height > ge2d_config->src2_planes[0].h)) { + ge2d_log_dbg("ge2d error: src2: alloc, out of range\n"); + return -1; + } + /*if (ge2d_config->src2_planes[0].addr == + * ge2d_config->src_planes[0].addr) + * index = ge2d_config->src_para.canvas_index; + * else + */ + if (ge2d_meson_dev.canvas_status == 1) { + if (ge2d_config_mem->src2_mem_alloc_type == + AML_GE2D_MEM_ION) { + if (build_ge2d_addr_config_ion( + &ge2d_config->src2_planes[0], + ge2d_config->src2_para.format, + &src2_addr, + &src2_stride) < 0) + return -1; + ge2d_log_dbg("ge2d ion alloc phy_addr:0x%x,stride=0x%x,format:0x%x\n", + src2_addr, + src2_stride, + ge2d_config->src2_para.format); + } else if (ge2d_config_mem->src2_mem_alloc_type == + AML_GE2D_MEM_DMABUF) { + if (build_ge2d_addr_config_dma( + &ge2d_config->src2_planes[0], + ge2d_config->src2_para.format, + &src2_addr, + &src2_stride, + DMA_TO_DEVICE) < 0) + return -1; + ge2d_log_dbg("ge2d dma alloc phy_addr:0x%x,stride=0x%x,format:0x%x\n", + src2_addr, + src2_stride, + ge2d_config->src2_para.format); + } + } else { + if (ge2d_config_mem->src2_mem_alloc_type == + AML_GE2D_MEM_ION) { + if (build_ge2d_config_ex_ion( + &ge2d_config->src2_planes[0], + ge2d_config->src2_para.format, + &index, + ALLOC_CANVAS_INDEX + + alloc_canvas_offset, + &alloc_canvas_offset) < 0) + return -1; + ge2d_config->src2_para.canvas_index = index; + ge2d_log_dbg("ge2d src2 ion alloc, canvas index:0x%x,format:0x%x\n", + index, ge2d_config->src2_para.format); + } else if (ge2d_config_mem->src2_mem_alloc_type == + AML_GE2D_MEM_DMABUF) { + if (build_ge2d_config_ex_dma( + &ge2d_config->src2_planes[0], + ge2d_config->src2_para.format, + &index, + ALLOC_CANVAS_INDEX + + alloc_canvas_offset, + &alloc_canvas_offset, + DMA_TO_DEVICE) < 0) + return -1; + ge2d_config->src2_para.canvas_index = index; + ge2d_log_dbg("ge2d src2 dma alloc, canvas index:0x%x,format:0x%x\n", + index, ge2d_config->src2_para.format); + } + } + break; + default: + break; + } + + switch (ge2d_config->dst_para.mem_type) { + case CANVAS_OSD0: + case CANVAS_OSD1: + if (setup_display_property(&tmp, + (ge2d_config->dst_para.mem_type == CANVAS_OSD0) ? + OSD1_CANVAS_INDEX : OSD2_CANVAS_INDEX) < 0) + return -1; + ge2d_config->dst_para.canvas_index = tmp.canvas_index; + ge2d_config->dst_para.format = tmp.ge2d_color_index; + dst_addr = tmp.phy_addr; + dst_stride = tmp.stride; + + ge2d_log_dbg("ge2d: dst-->type: osd%d, format: 0x%x !!\n", + ge2d_config->dst_para.mem_type - CANVAS_OSD0, + ge2d_config->dst_para.format); + + top = ge2d_config->dst_para.top; + left = ge2d_config->dst_para.left; + width = ge2d_config->dst_para.width; + height = ge2d_config->dst_para.height; + if ((left + width > tmp.xres) || (top + height > tmp.yres)) { + ge2d_log_dbg("ge2d error: dst: osd%d, out of range\n", + ge2d_config->dst_para.mem_type - CANVAS_OSD0); + return -1; + } + ge2d_config->dst_para.width = tmp.xres; + ge2d_config->dst_para.height = tmp.yres; + ge2d_log_dbg("ge2d osd phy_addr:0x%x,stride=0x%x,format:0x%x\n", + dst_addr, + dst_stride, + ge2d_config->dst_para.format); + break; + case CANVAS_ALLOC: + top = ge2d_config->dst_para.top; + left = ge2d_config->dst_para.left; + width = ge2d_config->dst_para.width; + height = ge2d_config->dst_para.height; + if ((left + width > ge2d_config->dst_planes[0].w) + || (top + height > ge2d_config->dst_planes[0].h)) { + ge2d_log_dbg("ge2d error: dst: alloc, out of range\n"); + return -1; + } + /*if (ge2d_config->dst_planes[0].addr == + * ge2d_config->src_planes[0].addr) + * index = ge2d_config->src_para.canvas_index; + * else if (ge2d_config->dst_planes[0].addr == + * ge2d_config->src2_planes[0].addr) + * index = ge2d_config->src2_para.canvas_index; + * else + */ + if (ge2d_meson_dev.canvas_status == 1) { + if (ge2d_config_mem->dst_mem_alloc_type == + AML_GE2D_MEM_ION) { + if (build_ge2d_addr_config_ion( + &ge2d_config->dst_planes[0], + ge2d_config->dst_para.format, + &dst_addr, + &dst_stride) < 0) + return -1; + ge2d_log_dbg("ge2d ion alloc phy_addr:0x%x,stride=0x%x,format:0x%x\n", + dst_addr, + dst_stride, + ge2d_config->dst_para.format); + } else if (ge2d_config_mem->dst_mem_alloc_type == + AML_GE2D_MEM_DMABUF) { + if (build_ge2d_addr_config_dma( + &ge2d_config->dst_planes[0], + ge2d_config->dst_para.format, + &dst_addr, + &dst_stride, + DMA_FROM_DEVICE) < 0) + return -1; + ge2d_log_dbg("ge2d dma alloc phy_addr:0x%x,stride=0x%x,format:0x%x\n", + dst_addr, + dst_stride, + ge2d_config->dst_para.format); + } + } else { + if (ge2d_config_mem->dst_mem_alloc_type == + AML_GE2D_MEM_ION) { + if (build_ge2d_config_ex_ion( + &ge2d_config->dst_planes[0], + ge2d_config->dst_para.format, + &index, + ALLOC_CANVAS_INDEX + + alloc_canvas_offset, + &alloc_canvas_offset) < 0) + return -1; + ge2d_config->dst_para.canvas_index = index; + ge2d_log_dbg("ge2d: dst ion alloc, index:0x%x, format:0x%x\n", + index, ge2d_config->dst_para.format); + } else if (ge2d_config_mem->dst_mem_alloc_type == + AML_GE2D_MEM_DMABUF) { + if (build_ge2d_config_ex_dma( + &ge2d_config->dst_planes[0], + ge2d_config->dst_para.format, + &index, + ALLOC_CANVAS_INDEX + + alloc_canvas_offset, + &alloc_canvas_offset, + DMA_FROM_DEVICE) < 0) + return -1; + ge2d_config->dst_para.canvas_index = index; + ge2d_log_dbg("ge2d: dst dma alloc, index:0x%x, format:0x%x\n", + index, ge2d_config->dst_para.format); + } + } + break; + default: + break; + } + + ge2dgen_rendering_dir(context, ge2d_config->src_para.x_rev, + ge2d_config->src_para.y_rev, + ge2d_config->dst_para.x_rev, + ge2d_config->dst_para.y_rev, + ge2d_config->dst_xy_swap); + ge2dgen_const_color(context, ge2d_config->alu_const_color); + + ge2dgen_src(context, ge2d_config->src_para.canvas_index, + ge2d_config->src_para.format, + src_addr, + src_stride); + ge2dgen_src_clip(context, ge2d_config->src_para.left, + ge2d_config->src_para.top, + ge2d_config->src_para.width, + ge2d_config->src_para.height); + ge2dgen_src_key(context, ge2d_config->src_key.key_enable, + ge2d_config->src_key.key_color, + ge2d_config->src_key.key_mask, + ge2d_config->src_key.key_mode); +#ifdef CONFIG_GE2D_SRC2 + ge2dgent_src_gbalpha(context, ge2d_config->src1_gb_alpha, + ge2d_config->src2_gb_alpha); +#else + ge2dgent_src_gbalpha(context, ge2d_config->src1_gb_alpha, 0); +#endif + ge2dgen_src_color(context, ge2d_config->src_para.color); + + ge2dgen_src2(context, ge2d_config->src2_para.canvas_index, + ge2d_config->src2_para.format, + src2_addr, + src2_stride); + ge2dgen_src2_clip(context, ge2d_config->src2_para.left, + ge2d_config->src2_para.top, + ge2d_config->src2_para.width, + ge2d_config->src2_para.height); + + ge2dgen_dst(context, ge2d_config->dst_para.canvas_index, + ge2d_config->dst_para.format, + dst_addr, + dst_stride); + ge2dgen_dst_clip(context, ge2d_config->dst_para.left, + ge2d_config->dst_para.top, + ge2d_config->dst_para.width, + ge2d_config->dst_para.height, + DST_CLIP_MODE_INSIDE); + + src1_gen_cfg = ge2d_wq_get_src_gen(context); + src1_gen_cfg->fill_mode = ge2d_config->src_para.fill_mode; + src1_gen_cfg->chfmt_rpt_pix = 0; + src1_gen_cfg->cvfmt_rpt_pix = 0; + /* src1_gen_cfg->clipx_start_ex = 0; */ + /* src1_gen_cfg->clipx_end_ex = 1; */ + /* src1_gen_cfg->clipy_start_ex = 1; */ + /* src1_gen_cfg->clipy_end_ex = 1; */ + + src2_dst_data_cfg = ge2d_wq_get_dst_data(context); + src2_dst_data_cfg->src2_def_color = ge2d_config->src2_para.color; + + src2_dst_gen_cfg = ge2d_wq_get_dst_gen(context); + src2_dst_gen_cfg->src2_fill_mode = ge2d_config->src2_para.fill_mode; + + dp_gen_cfg = ge2d_wq_get_dp_gen(context); + + dp_gen_cfg->src1_vsc_phase0_always_en = + ge2d_config->src1_hsc_phase0_always_en; + dp_gen_cfg->src1_hsc_phase0_always_en = + ge2d_config->src1_vsc_phase0_always_en; + if ((context->config.v_scale_coef_type == FILTER_TYPE_GAU0) || + (context->config.v_scale_coef_type == FILTER_TYPE_GAU0_BOT) || + (context->config.v_scale_coef_type == FILTER_TYPE_GAU1) || + (context->config.h_scale_coef_type == FILTER_TYPE_GAU0) || + (context->config.h_scale_coef_type == FILTER_TYPE_GAU0_BOT) || + (context->config.h_scale_coef_type == FILTER_TYPE_GAU1)) { + /* 1bit, 0: using minus, 1: using repeat data */ + dp_gen_cfg->src1_hsc_rpt_ctrl = ge2d_config->src1_hsc_rpt_ctrl; + /* 1bit, 0: using minus 1: using repeat data */ + dp_gen_cfg->src1_vsc_rpt_ctrl = ge2d_config->src1_vsc_rpt_ctrl; + } else { + /* 1bit, 0: using minus, 1: using repeat data */ + dp_gen_cfg->src1_hsc_rpt_ctrl = 1; + /* 1bit, 0: using minus 1: using repeat data */ + dp_gen_cfg->src1_vsc_rpt_ctrl = 1; + } + dp_gen_cfg->src1_gb_alpha = ge2d_config->src1_gb_alpha & 0xff; + dp_gen_cfg->src1_gb_alpha_en = ge2d_config->src1_gb_alpha_en & 1; +#ifdef CONFIG_GE2D_SRC2 + dp_gen_cfg->src2_gb_alpha = ge2d_config->src2_gb_alpha & 0xff; + dp_gen_cfg->src2_gb_alpha_en = ge2d_config->src2_gb_alpha_en & 1; +#endif + dp_gen_cfg->src2_key_en = ge2d_config->src2_key.key_enable; + dp_gen_cfg->src2_key_mode = ge2d_config->src2_key.key_mode; + dp_gen_cfg->src2_key = ge2d_config->src2_key.key_color; + dp_gen_cfg->src2_key_mask = ge2d_config->src2_key.key_mask; + + dp_gen_cfg->bitmask_en = ge2d_config->bitmask_en; + dp_gen_cfg->bitmask = ge2d_config->bitmask; + dp_gen_cfg->bytemask_only = ge2d_config->bytemask_only; + + ge2d_cmd_cfg = ge2d_wq_get_cmd(context); + + ge2d_cmd_cfg->src1_fill_color_en = ge2d_config->src_para.fill_color_en; + + ge2d_cmd_cfg->src2_x_rev = ge2d_config->src2_para.x_rev; + ge2d_cmd_cfg->src2_y_rev = ge2d_config->src2_para.y_rev; + ge2d_cmd_cfg->src2_fill_color_en = + ge2d_config->src2_para.fill_color_en; +#ifdef CONFIG_GE2D_SRC2 + ge2d_cmd_cfg->src2_cmult_ad = ge2d_config->src2_cmult_ad; +#endif + + ge2d_cmd_cfg->vsc_phase_slope = ge2d_config->vsc_phase_slope; + ge2d_cmd_cfg->vsc_ini_phase = ge2d_config->vf_init_phase; + ge2d_cmd_cfg->vsc_phase_step = ge2d_config->vsc_start_phase_step; + ge2d_cmd_cfg->vsc_rpt_l0_num = ge2d_config->vf_rpt_num; + + /* let internal decide */ + ge2d_cmd_cfg->hsc_phase_slope = ge2d_config->hsc_phase_slope; + ge2d_cmd_cfg->hsc_ini_phase = ge2d_config->hf_init_phase; + ge2d_cmd_cfg->hsc_phase_step = ge2d_config->hsc_start_phase_step; + ge2d_cmd_cfg->hsc_rpt_p0_num = ge2d_config->hf_rpt_num; + ge2d_cmd_cfg->src1_cmult_asel = ge2d_config->src1_cmult_asel; + ge2d_cmd_cfg->src2_cmult_asel = ge2d_config->src2_cmult_asel; + context->config.update_flag = UPDATE_ALL; + /* context->config.src1_data.ddr_burst_size_y = 3; */ + /* context->config.src1_data.ddr_burst_size_cb = 3; */ + /* context->config.src1_data.ddr_burst_size_cr = 3; */ + /* context->config.src2_dst_data.ddr_burst_size= 3; */ + + return 0; +} + +int ge2d_buffer_alloc(struct ge2d_dmabuf_req_s *ge2d_req_buf) +{ + struct device *dev; + + dev = &(ge2d_manager.pdev->dev); + return ge2d_dma_buffer_alloc(ge2d_manager.buffer, + dev, ge2d_req_buf); +} + +int ge2d_buffer_export(struct ge2d_dmabuf_exp_s *ge2d_exp_buf) +{ + return ge2d_dma_buffer_export(ge2d_manager.buffer, ge2d_exp_buf); +} + +int ge2d_buffer_free(int index) +{ + return ge2d_dma_buffer_free(ge2d_manager.buffer, index); + +} + +void ge2d_buffer_dma_flush(int dma_fd) +{ + struct device *dev; + + dev = &(ge2d_manager.pdev->dev); + ge2d_dma_buffer_dma_flush(dev, dma_fd); +} + +void ge2d_buffer_cache_flush(int dma_fd) +{ + struct device *dev; + + dev = &(ge2d_manager.pdev->dev); + ge2d_dma_buffer_cache_flush(dev, dma_fd); +} + +struct ge2d_context_s *create_ge2d_work_queue(void) +{ + int i; + struct ge2d_queue_item_s *p_item; + struct ge2d_context_s *ge2d_work_queue; + int empty; + + ge2d_work_queue = kzalloc(sizeof(struct ge2d_context_s), GFP_KERNEL); + ge2d_work_queue->config.h_scale_coef_type = FILTER_TYPE_BILINEAR; + ge2d_work_queue->config.v_scale_coef_type = FILTER_TYPE_BILINEAR; + ge2d_work_queue->ge2d_request_exit = 0; + if (IS_ERR(ge2d_work_queue)) { + ge2d_log_err("can't create work queue\n"); + return NULL; + } + INIT_LIST_HEAD(&ge2d_work_queue->work_queue); + INIT_LIST_HEAD(&ge2d_work_queue->free_queue); + init_waitqueue_head(&ge2d_work_queue->cmd_complete); + spin_lock_init(&ge2d_work_queue->lock); /* for process lock. */ + for (i = 0; i < MAX_GE2D_CMD; i++) { + p_item = kcalloc(1, + sizeof(struct ge2d_queue_item_s), + GFP_KERNEL); + if (IS_ERR(p_item)) { + ge2d_log_err("can't request queue item memory\n"); + return NULL; + } + list_add_tail(&p_item->list, &ge2d_work_queue->free_queue); + } + + /* put this process queue into manager queue list. */ + /* maybe process queue is changing . */ + spin_lock(&ge2d_manager.event.sem_lock); + empty = list_empty(&ge2d_manager.process_queue); + list_add_tail(&ge2d_work_queue->list, &ge2d_manager.process_queue); + spin_unlock(&ge2d_manager.event.sem_lock); + return ge2d_work_queue; /* find it */ +} +EXPORT_SYMBOL(create_ge2d_work_queue); + +int destroy_ge2d_work_queue(struct ge2d_context_s *ge2d_work_queue) +{ + struct ge2d_queue_item_s *pitem, *tmp; + struct list_head *head; + int empty, timeout = 0; + + if (ge2d_work_queue) { + /* first detatch it from the process queue,then delete it . */ + /* maybe process queue is changing .so we lock it. */ + spin_lock(&ge2d_manager.event.sem_lock); + list_del(&ge2d_work_queue->list); + empty = list_empty(&ge2d_manager.process_queue); + spin_unlock(&ge2d_manager.event.sem_lock); + if ((ge2d_manager.current_wq == ge2d_work_queue) && + (ge2d_manager.ge2d_state == GE2D_STATE_RUNNING)) { + ge2d_work_queue->ge2d_request_exit = 1; + timeout = wait_for_completion_timeout( + &ge2d_manager.event.process_complete, + msecs_to_jiffies(500)); + if (!timeout) + ge2d_log_err("wait timeout\n"); + /* condition so complex ,simplify it . */ + ge2d_manager.last_wq = NULL; + } /* else we can delete it safely. */ + + head = &ge2d_work_queue->work_queue; + list_for_each_entry_safe(pitem, tmp, head, list) { + if (pitem) { + list_del(&pitem->list); + kfree(pitem); + } + } + head = &ge2d_work_queue->free_queue; + list_for_each_entry_safe(pitem, tmp, head, list) { + if (pitem) { + list_del(&pitem->list); + kfree(pitem); + } + } + + kfree(ge2d_work_queue); + ge2d_work_queue = NULL; + return 0; + } + + return -1; +} +EXPORT_SYMBOL(destroy_ge2d_work_queue); + +int ge2d_wq_init(struct platform_device *pdev, + int irq, struct clk *clk) +{ + struct ge2d_gen_s ge2d_gen_cfg; ge2d_manager.pdev = pdev; ge2d_irq = irq; @@ -1933,6 +2565,9 @@ int ge2d_wq_init(struct platform_device *pdev, INIT_LIST_HEAD(&ge2d_manager.process_queue); ge2d_manager.last_wq = NULL; ge2d_manager.ge2d_thread = NULL; + ge2d_manager.buffer = ge2d_dma_buffer_create(); + if (!ge2d_manager.buffer) + return -1; ge2d_clk_config(true); ge2d_soft_rst(); ge2d_gen_cfg.interrupt_ctrl = 0x02; @@ -1966,6 +2601,8 @@ int ge2d_wq_deinit(void) } ge2d_irq = -1; clk_disable_unprepare(ge2d_clk); + ge2d_dma_buffer_destroy(ge2d_manager.buffer); + ge2d_manager.buffer = NULL; ge2d_manager.pdev = NULL; return 0; } diff --git a/drivers/amlogic/media/common/ge2d/ge2d_wq.h b/drivers/amlogic/media/common/ge2d/ge2d_wq.h index 00b7a29..2fd0678 100644 --- a/drivers/amlogic/media/common/ge2d/ge2d_wq.h +++ b/drivers/amlogic/media/common/ge2d/ge2d_wq.h @@ -34,4 +34,9 @@ extern int ge2d_wq_init(struct platform_device *pdev, int irq, struct clk *clk); extern int ge2d_wq_deinit(void); +int ge2d_buffer_alloc(struct ge2d_dmabuf_req_s *ge2d_req_buf); +int ge2d_buffer_free(int index); +int ge2d_buffer_export(struct ge2d_dmabuf_exp_s *ge2d_exp_buf); +void ge2d_buffer_dma_flush(int dma_fd); +void ge2d_buffer_cache_flush(int dma_fd); #endif diff --git a/include/linux/amlogic/media/ge2d/ge2d.h b/include/linux/amlogic/media/ge2d/ge2d.h index 1b90af6..cdcf0de 100644 --- a/include/linux/amlogic/media/ge2d/ge2d.h +++ b/include/linux/amlogic/media/ge2d/ge2d.h @@ -27,6 +27,12 @@ #include #endif +enum ge2d_memtype_s { + AML_GE2D_MEM_ION, + AML_GE2D_MEM_DMABUF, + AML_GE2D_MEM_INVALID, +}; + #define MAX_BITBLT_WORK_CONFIG 4 #define MAX_GE2D_CMD 32 /* 64 */ @@ -612,6 +618,12 @@ struct ge2d_config_s { unsigned int update_flag; }; +struct ge2d_dma_buf_s { + dma_addr_t paddr; + void *vaddr; + int len; +}; + enum ge2d_src_dst_e { OSD0_OSD0 = 0, OSD0_OSD1, @@ -665,6 +677,7 @@ struct ge2d_manager_s { struct ge2d_context_s *last_wq; struct task_struct *ge2d_thread; struct ge2d_event_s event; + struct aml_dma_buffer *buffer; int irq_num; int ge2d_state; int process_queue_state; @@ -951,6 +964,56 @@ struct compat_config_para_ex_ion_s { struct compat_config_planes_ion_s dst_planes[4]; }; #endif + +struct config_para_ex_memtype_s { + int ge2d_magic; + struct config_para_ex_ion_s _ge2d_config_ex; + /* memtype*/ + unsigned int src1_mem_alloc_type; + unsigned int src2_mem_alloc_type; + unsigned int dst_mem_alloc_type; +}; + +struct config_ge2d_para_ex_s { + union { + struct config_para_ex_ion_s para_config_ion; + struct config_para_ex_memtype_s para_config_memtype; + }; +}; + + +#ifdef CONFIG_COMPAT +struct compat_config_para_ex_memtype_s { + int ge2d_magic; + struct compat_config_para_ex_ion_s _ge2d_config_ex; + /* memtype*/ + unsigned int src1_mem_alloc_type; + unsigned int src2_mem_alloc_type; + unsigned int dst_mem_alloc_type; +}; + +struct compat_config_ge2d_para_ex_s { + union { + struct compat_config_para_ex_ion_s para_config_ion; + struct compat_config_para_ex_memtype_s para_config_memtype; + }; +}; +#endif + +/* for ge2d dma buf define */ +struct ge2d_dmabuf_req_s { + int index; + unsigned int len; + unsigned int dma_dir; +}; + +struct ge2d_dmabuf_exp_s { + int index; + unsigned int flags; + int fd; +}; +/* end of ge2d dma buffer define */ + struct ge2d_device_data_s { int ge2d_rate; int src2_alp; @@ -992,6 +1055,21 @@ extern struct ge2d_device_data_s ge2d_meson_dev; _IOW(GE2D_IOC_MAGIC, 0x03, struct compat_config_para_ex_ion_s) #endif +#define GE2D_REQUEST_BUFF _IOW(GE2D_IOC_MAGIC, 0x04, struct ge2d_dmabuf_req_s) +#define GE2D_EXP_BUFF _IOW(GE2D_IOC_MAGIC, 0x05, struct ge2d_dmabuf_exp_s) +#define GE2D_FREE_BUFF _IOW(GE2D_IOC_MAGIC, 0x06, int) + +#define GE2D_CONFIG_EX_MEM \ + _IOW(GE2D_IOC_MAGIC, 0x07, struct config_ge2d_para_ex_s) + +#ifdef CONFIG_COMPAT +#define GE2D_CONFIG_EX32_MEM \ + _IOW(GE2D_IOC_MAGIC, 0x07, struct compat_config_ge2d_para_ex_s) +#endif + +#define GE2D_SYNC_DEVICE _IOW(GE2D_IOC_MAGIC, 0x08, int) +#define GE2D_SYNC_CPU _IOW(GE2D_IOC_MAGIC, 0x09, int) + extern void ge2d_set_src1_data(struct ge2d_src1_data_s *cfg); extern void ge2d_set_src1_gen(struct ge2d_src1_gen_s *cfg); extern void ge2d_set_src2_dst_data(struct ge2d_src2_dst_data_s *cfg); @@ -1012,6 +1090,8 @@ extern int ge2d_context_config_ex(struct ge2d_context_s *context, struct config_para_ex_s *ge2d_config); extern int ge2d_context_config_ex_ion(struct ge2d_context_s *context, struct config_para_ex_ion_s *ge2d_config); +extern int ge2d_context_config_ex_mem(struct ge2d_context_s *context, + struct config_para_ex_memtype_s *ge2d_config_mem); extern struct ge2d_context_s *create_ge2d_work_queue(void); extern int destroy_ge2d_work_queue(struct ge2d_context_s *wq); extern int ge2d_wq_remove_config(struct ge2d_context_s *wq); -- 2.7.4