From c291135f0c534d3e20a2f8f70929953fbd3424f2 Mon Sep 17 00:00:00 2001 From: Pengcheng Chen Date: Fri, 11 Jan 2019 10:54:46 +0800 Subject: [PATCH] gdc: add gdc dma_buf input/output support [2/2] PD#SWPL-4036 Problem: gdc don't support export dma_buf Solution: add gdc dma_buf input/output support Verify: test pass on w400 Change-Id: I67a60ede01e5c01630a00fbae2821430a870c2b8 Signed-off-by: Pengcheng Chen --- MAINTAINERS | 8 +- drivers/amlogic/media/gdc/Makefile | 4 +- drivers/amlogic/media/gdc/app/gdc_dmabuf.c | 636 ++++++++++++++++++++ drivers/amlogic/media/gdc/app/gdc_dmabuf.h | 79 +++ drivers/amlogic/media/gdc/app/gdc_main.c | 16 +- drivers/amlogic/media/gdc/app/gdc_module.c | 660 ++++++++++++++++----- drivers/amlogic/media/gdc/inc/api/gdc_api.h | 120 +++- drivers/amlogic/media/gdc/inc/gdc/gdc_config.h | 12 +- drivers/amlogic/media/gdc/inc/sys/system_log.h | 23 +- drivers/amlogic/media/gdc/src/fw_lib/acamera_gdc.c | 152 ++--- .../amlogic/media/gdc/src/platform/system_gdc_io.c | 20 +- 11 files changed, 1440 insertions(+), 290 deletions(-) create mode 100644 drivers/amlogic/media/gdc/app/gdc_dmabuf.c create mode 100644 drivers/amlogic/media/gdc/app/gdc_dmabuf.h diff --git a/MAINTAINERS b/MAINTAINERS index 2ad404f..173d580 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14770,4 +14770,10 @@ 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 +F: drivers/amlogic/media/common/ge2d/ge2d_dmabuf.h + +AMLOGIC GDC DRIVER +M: Pengcheng Chen +F: drivers/amlogic/media/gdc/app/gdc_dmabuf.c +F: drivers/amlogic/media/gdc/app/gdc_dmabuf.h +F: drivers/amlogic/media/gdc/src/platform/system_log.c \ No newline at end of file diff --git a/drivers/amlogic/media/gdc/Makefile b/drivers/amlogic/media/gdc/Makefile index 5892420..d0d4b27 100644 --- a/drivers/amlogic/media/gdc/Makefile +++ b/drivers/amlogic/media/gdc/Makefile @@ -1,8 +1,8 @@ FW_SRC := src/fw_lib/acamera_gdc.c \ src/platform/system_gdc_io.c \ - src/platform/system_log.c \ app/gdc_main.c \ - app/gdc_module.c + app/gdc_module.c \ + app/gdc_dmabuf.c FW_SRC_OBJ := $(FW_SRC:.c=.o) diff --git a/drivers/amlogic/media/gdc/app/gdc_dmabuf.c b/drivers/amlogic/media/gdc/app/gdc_dmabuf.c new file mode 100644 index 0000000..2f4fe59 --- /dev/null +++ b/drivers/amlogic/media/gdc/app/gdc_dmabuf.c @@ -0,0 +1,636 @@ +/* + * drivers/amlogic/media/gdc/app/gdc_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 + +#include "system_log.h" +#include "gdc_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)) { + gdc_log(LOG_INFO, "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); + gdc_log(LOG_INFO, "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); + gdc_log(LOG_INFO, "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; + } + gdc_log(LOG_INFO, "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 gdc_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 = &gdc_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); + gdc_log(LOG_INFO, "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 { + gdc_log(LOG_INFO, "find_empty_dma_buffer i=%d\n", i); + found = 1; + break; + } + } + if (found) + return i; + else + return -1; +} + +void *gdc_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 gdc_dma_buffer_destroy(struct aml_dma_buffer *buffer) +{ + kfree(buffer); +} + +int gdc_dma_buffer_alloc(struct aml_dma_buffer *buffer, + struct device *dev, + struct gdc_dmabuf_req_s *gdc_req_buf) +{ + void *buf; + unsigned int size; + int index; + + if (WARN_ON(!dev)) + return (-EINVAL); + if (!gdc_req_buf) + return (-EINVAL); + if (!buffer) + return (-EINVAL); + + size = PAGE_ALIGN(gdc_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, gdc_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)); + gdc_req_buf->index = index; + return 0; +} + +int gdc_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 gdc_dma_buffer_export(struct aml_dma_buffer *buffer, + struct gdc_dmabuf_exp_s *gdc_exp_buf) +{ + struct aml_dma_buf *buf; + struct dma_buf *dbuf; + int ret, index; + unsigned int flags; + + if (!gdc_exp_buf) + return (-EINVAL); + if (!buffer) + return (-EINVAL); + + index = gdc_exp_buf->index; + if ((index) < 0 || (index >= AML_MAX_DMABUF)) + return (-EINVAL); + + flags = gdc_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; + } + + gdc_log(LOG_INFO, "buffer %d,exported as %d descriptor\n", + index, ret); + gdc_exp_buf->fd = ret; + return 0; +} + +int gdc_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 gdc_dma_buffer_get_phys(struct aml_dma_cfg *cfg, unsigned long *addr) +{ + struct sg_table *sg_table; + struct page *page; + int ret; + + ret = gdc_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; + } + gdc_dma_buffer_unmap(cfg); + return ret; +} + +void gdc_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 gdc_dma_buffer_dma_flush(struct device *dev, int fd) +{ + struct dma_buf *dmabuf; + struct aml_dma_buf *buf; + + gdc_log(LOG_INFO, "gdc_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 gdc_dma_buffer_cache_flush(struct device *dev, int fd) +{ + struct dma_buf *dmabuf; + struct aml_dma_buf *buf; + + gdc_log(LOG_INFO, "gdc_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/gdc/app/gdc_dmabuf.h b/drivers/amlogic/media/gdc/app/gdc_dmabuf.h new file mode 100644 index 0000000..6de1d57 --- /dev/null +++ b/drivers/amlogic/media/gdc/app/gdc_dmabuf.h @@ -0,0 +1,79 @@ +/* + * drivers/amlogic/media/gdc/app/gdc_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 _GDC_DMABUF_H_ +#define _GDC_DMABUF_H_ + +#include +#include +#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 *gdc_dma_buffer_create(void); +void gdc_dma_buffer_destroy(struct aml_dma_buffer *buffer); +int gdc_dma_buffer_alloc(struct aml_dma_buffer *buffer, + struct device *dev, + struct gdc_dmabuf_req_s *gdc_req_buf); +int gdc_dma_buffer_free(struct aml_dma_buffer *buffer, int index); +int gdc_dma_buffer_export(struct aml_dma_buffer *buffer, + struct gdc_dmabuf_exp_s *gdc_exp_buf); +int gdc_dma_buffer_map(struct aml_dma_cfg *cfg); +void gdc_dma_buffer_unmap(struct aml_dma_cfg *cfg); +int gdc_dma_buffer_get_phys(struct aml_dma_cfg *cfg, unsigned long *addr); +void gdc_dma_buffer_dma_flush(struct device *dev, int fd); +void gdc_dma_buffer_cache_flush(struct device *dev, int fd); +#endif diff --git a/drivers/amlogic/media/gdc/app/gdc_main.c b/drivers/amlogic/media/gdc/app/gdc_main.c index c6d6311..538416d 100644 --- a/drivers/amlogic/media/gdc/app/gdc_main.c +++ b/drivers/amlogic/media/gdc/app/gdc_main.c @@ -25,27 +25,27 @@ irqreturn_t interrupt_handler_next(int irq, void *param) { //handle the start of frame with gdc_process - struct gdc_settings *gdc_settings = (struct gdc_settings *)param; + struct gdc_cmd_s *gdc_cmd = (struct gdc_cmd_s *)param; - gdc_get_frame(gdc_settings); + gdc_get_frame(gdc_cmd); return IRQ_HANDLED; } -int gdc_run(struct gdc_settings *g) +int gdc_run(struct gdc_cmd_s *g) { gdc_stop(g); - LOG(LOG_INFO, "Done gdc load..\n"); + gdc_log(LOG_INFO, "Done gdc load..\n"); //initialise the gdc by the first configuration if (gdc_init(g) != 0) { - LOG(LOG_ERR, "Failed to initialise GDC block"); + gdc_log(LOG_ERR, "Failed to initialise GDC block"); return -1; } - LOG(LOG_INFO, "Done gdc config..\n"); + gdc_log(LOG_INFO, "Done gdc config..\n"); switch (g->gdc_config.format) { case NV12: @@ -70,10 +70,10 @@ int gdc_run(struct gdc_settings *g) g->v_base_addr); break; default: - LOG(LOG_ERR, "Error config format\n"); + gdc_log(LOG_ERR, "Error config format\n"); break; } - LOG(LOG_DEBUG, "call gdc process\n"); + gdc_log(LOG_DEBUG, "call gdc process\n"); return 0; } diff --git a/drivers/amlogic/media/gdc/app/gdc_module.c b/drivers/amlogic/media/gdc/app/gdc_module.c index 040218d..e0f1dad 100644 --- a/drivers/amlogic/media/gdc/app/gdc_module.c +++ b/drivers/amlogic/media/gdc/app/gdc_module.c @@ -43,8 +43,10 @@ #include //gdc configuration sequence #include "gdc_config.h" +#include "gdc_dmabuf.h" -struct meson_gdc_dev_t *g_gdc_dev; +unsigned int gdc_log_level; +struct gdc_manager_s gdc_manager; static const struct of_device_id gdc_dt_match[] = { {.compatible = "amlogic, g12b-gdc"}, @@ -55,19 +57,19 @@ MODULE_DEVICE_TABLE(of, gdc_dt_match); ////// static int meson_gdc_open(struct inode *inode, struct file *file) { - struct meson_gdc_dev_t *gdc_dev = g_gdc_dev; + struct meson_gdc_dev_t *gdc_dev = gdc_manager.gdc_dev; struct mgdc_fh_s *fh = NULL; char ion_client_name[32]; int rc = 0; fh = kzalloc(sizeof(*fh), GFP_KERNEL); if (fh == NULL) { - LOG(LOG_DEBUG, "devm alloc failed\n"); + gdc_log(LOG_DEBUG, "devm alloc failed\n"); return -ENOMEM; } get_task_comm(fh->task_comm, current); - LOG(LOG_DEBUG, "%s, %d, call from %s\n", + gdc_log(LOG_DEBUG, "%s, %d, call from %s\n", __func__, __LINE__, fh->task_comm); file->private_data = fh; @@ -78,7 +80,7 @@ static int meson_gdc_open(struct inode *inode, struct file *file) fh->gdev = gdc_dev; - LOG(LOG_CRIT, "Success open\n"); + gdc_log(LOG_CRIT, "Success open\n"); return rc; } @@ -102,7 +104,7 @@ static int meson_gdc_release(struct inode *inode, struct file *file) fh->i_len >> PAGE_SHIFT); if (rc == false) { ret = ret - 1; - LOG(LOG_ERR, "Failed to release input buff\n"); + gdc_log(LOG_ERR, "Failed to release input buff\n"); } fh->i_kaddr = NULL; @@ -117,7 +119,7 @@ static int meson_gdc_release(struct inode *inode, struct file *file) fh->o_len >> PAGE_SHIFT); if (rc == false) { ret = ret - 1; - LOG(LOG_ERR, "Failed to release output buff\n"); + gdc_log(LOG_ERR, "Failed to release output buff\n"); } fh->o_kaddr = NULL; @@ -132,7 +134,7 @@ static int meson_gdc_release(struct inode *inode, struct file *file) fh->c_len >> PAGE_SHIFT); if (rc == false) { ret = ret - 1; - LOG(LOG_ERR, "Failed to release config buff\n"); + gdc_log(LOG_ERR, "Failed to release config buff\n"); } fh->c_kaddr = NULL; @@ -144,9 +146,9 @@ static int meson_gdc_release(struct inode *inode, struct file *file) fh = NULL; if (ret == 0) - LOG(LOG_CRIT, "Success release\n"); + gdc_log(LOG_CRIT, "Success release\n"); else - LOG(LOG_ERR, "Error release\n"); + gdc_log(LOG_ERR, "Error release\n"); return ret; } @@ -159,7 +161,7 @@ static long meson_gdc_set_buff(void *f_fh, struct mgdc_fh_s *fh = NULL; if (f_fh == NULL || cma_pages == NULL || len == 0) { - LOG(LOG_ERR, "Error input param\n"); + gdc_log(LOG_ERR, "Error input param\n"); return -EINVAL; } @@ -188,7 +190,7 @@ static long meson_gdc_set_buff(void *f_fh, fh->c_len = len; break; default: - LOG(LOG_ERR, "Error mmap type:0x%x\n", fh->mmap_type); + gdc_log(LOG_ERR, "Error mmap type:0x%x\n", fh->mmap_type); ret = -EINVAL; break; } @@ -197,51 +199,51 @@ static long meson_gdc_set_buff(void *f_fh, } static long meson_gdc_set_input_addr(uint32_t start_addr, - struct gdc_settings *gs) + struct gdc_cmd_s *gdc_cmd) { - struct gdc_config *gc = NULL; + struct gdc_config_s *gc = NULL; - if (gs == NULL || start_addr == 0) { - LOG(LOG_ERR, "Error input param\n"); + if (gdc_cmd == NULL || start_addr == 0) { + gdc_log(LOG_ERR, "Error input param\n"); return -EINVAL; } - gc = &gs->gdc_config; + gc = &gdc_cmd->gdc_config; switch (gc->format) { case NV12: - gs->y_base_addr = start_addr; - gs->uv_base_addr = start_addr + + gdc_cmd->y_base_addr = start_addr; + gdc_cmd->uv_base_addr = start_addr + gc->input_y_stride * gc->input_height; break; case YV12: - gs->y_base_addr = start_addr; - gs->u_base_addr = start_addr + + gdc_cmd->y_base_addr = start_addr; + gdc_cmd->u_base_addr = start_addr + gc->input_y_stride * gc->input_height; - gs->v_base_addr = gs->u_base_addr + + gdc_cmd->v_base_addr = gdc_cmd->u_base_addr + gc->input_c_stride * gc->input_height / 2; break; case Y_GREY: - gs->y_base_addr = start_addr; - gs->u_base_addr = 0; - gs->v_base_addr = 0; + gdc_cmd->y_base_addr = start_addr; + gdc_cmd->u_base_addr = 0; + gdc_cmd->v_base_addr = 0; break; case YUV444_P: - gs->y_base_addr = start_addr; - gs->u_base_addr = start_addr + + gdc_cmd->y_base_addr = start_addr; + gdc_cmd->u_base_addr = start_addr + gc->input_y_stride * gc->input_height; - gs->v_base_addr = gs->u_base_addr + + gdc_cmd->v_base_addr = gdc_cmd->u_base_addr + gc->input_c_stride * gc->input_height; break; case RGB444_P: - gs->y_base_addr = start_addr; - gs->u_base_addr = start_addr + + gdc_cmd->y_base_addr = start_addr; + gdc_cmd->u_base_addr = start_addr + gc->input_y_stride * gc->input_height; - gs->v_base_addr = gs->u_base_addr + + gdc_cmd->v_base_addr = gdc_cmd->u_base_addr + gc->input_c_stride * gc->input_height; break; default: - LOG(LOG_ERR, "Error config format\n"); + gdc_log(LOG_ERR, "Error config format\n"); return -EINVAL; break; } @@ -254,7 +256,7 @@ static void meson_gdc_dma_flush(struct device *dev, size_t size) { if (dev == NULL) { - LOG(LOG_ERR, "Error input param"); + gdc_log(LOG_ERR, "Error input param"); return; } @@ -266,7 +268,7 @@ static void meson_gdc_cache_flush(struct device *dev, size_t size) { if (dev == NULL) { - LOG(LOG_ERR, "Error input param"); + gdc_log(LOG_ERR, "Error input param"); return; } @@ -285,7 +287,7 @@ static long meson_gdc_dma_map(struct gdc_dma_cfg *cfg) enum dma_data_direction dir; if (cfg == NULL || (cfg->fd < 0) || cfg->dev == NULL) { - LOG(LOG_ERR, "Error input param"); + gdc_log(LOG_ERR, "Error input param"); return -EINVAL; } @@ -295,31 +297,31 @@ static long meson_gdc_dma_map(struct gdc_dma_cfg *cfg) dbuf = dma_buf_get(fd); if (dbuf == NULL) { - LOG(LOG_ERR, "Failed to get dma buffer"); + gdc_log(LOG_ERR, "Failed to get dma buffer"); return -EINVAL; } d_att = dma_buf_attach(dbuf, dev); if (d_att == NULL) { - LOG(LOG_ERR, "Failed to set dma attach"); + gdc_log(LOG_ERR, "Failed to set dma attach"); goto attach_err; } sg = dma_buf_map_attachment(d_att, dir); if (sg == NULL) { - LOG(LOG_ERR, "Failed to get dma sg"); + gdc_log(LOG_ERR, "Failed to get dma sg"); goto map_attach_err; } ret = dma_buf_begin_cpu_access(dbuf, dir); if (ret != 0) { - LOG(LOG_ERR, "Failed to access dma buff"); + gdc_log(LOG_ERR, "Failed to access dma buff"); goto access_err; } vaddr = dma_buf_vmap(dbuf); if (vaddr == NULL) { - LOG(LOG_ERR, "Failed to vmap dma buf"); + gdc_log(LOG_ERR, "Failed to vmap dma buf"); goto vmap_err; } @@ -359,7 +361,7 @@ static void meson_gdc_dma_unmap(struct gdc_dma_cfg *cfg) if (cfg == NULL || (cfg->fd < 0) || cfg->dev == NULL || cfg->dbuf == NULL || cfg->vaddr == NULL || cfg->attach == NULL || cfg->sg == NULL) { - LOG(LOG_ERR, "Error input param"); + gdc_log(LOG_ERR, "Error input param"); return; } @@ -382,21 +384,19 @@ static void meson_gdc_dma_unmap(struct gdc_dma_cfg *cfg) dma_buf_put(dbuf); } -static long meson_gdc_init_dma_addr(struct gdc_settings *gs) +static long meson_gdc_init_dma_addr(struct mgdc_fh_s *fh, + struct gdc_settings *gs) { long ret = -1; struct gdc_dma_cfg *dma_cfg = NULL; - struct gdc_config *gc = NULL; - struct mgdc_fh_s *fh = NULL; + struct gdc_cmd_s *gdc_cmd = &fh->gdc_cmd; + struct gdc_config_s *gc = &gdc_cmd->gdc_config; - if (gs == NULL || gs->fh == NULL) { - LOG(LOG_ERR, "Error input param\n"); + if (fh == NULL || gs == NULL) { + gdc_log(LOG_ERR, "Error input param\n"); return -EINVAL; } - gc = &gs->gdc_config; - fh = gs->fh; - switch (gc->format) { case NV12: dma_cfg = &fh->y_dma_cfg; @@ -407,11 +407,11 @@ static long meson_gdc_init_dma_addr(struct gdc_settings *gs) ret = meson_gdc_dma_map(dma_cfg); if (ret != 0) { - LOG(LOG_ERR, "Failed to get map dma buff"); + gdc_log(LOG_ERR, "Failed to get map dma buff"); return ret; } - gs->y_base_addr = virt_to_phys(dma_cfg->vaddr); + gdc_cmd->y_base_addr = virt_to_phys(dma_cfg->vaddr); dma_cfg = &fh->uv_dma_cfg; memset(dma_cfg, 0, sizeof(*dma_cfg)); @@ -421,11 +421,11 @@ static long meson_gdc_init_dma_addr(struct gdc_settings *gs) ret = meson_gdc_dma_map(dma_cfg); if (ret != 0) { - LOG(LOG_ERR, "Failed to get map dma buff"); + gdc_log(LOG_ERR, "Failed to get map dma buff"); return ret; } - gs->uv_base_addr = virt_to_phys(dma_cfg->vaddr); + gdc_cmd->uv_base_addr = virt_to_phys(dma_cfg->vaddr); break; case Y_GREY: dma_cfg = &fh->y_dma_cfg; @@ -436,35 +436,31 @@ static long meson_gdc_init_dma_addr(struct gdc_settings *gs) ret = meson_gdc_dma_map(dma_cfg); if (ret != 0) { - LOG(LOG_ERR, "Failed to get map dma buff"); + gdc_log(LOG_ERR, "Failed to get map dma buff"); return ret; } - - gs->y_base_addr = virt_to_phys(dma_cfg->vaddr); - gs->uv_base_addr = 0; + gdc_cmd->y_base_addr = virt_to_phys(dma_cfg->vaddr); + gdc_cmd->uv_base_addr = 0; break; default: - LOG(LOG_ERR, "Error image format"); + gdc_log(LOG_ERR, "Error image format"); break; } return ret; } -static void meson_gdc_deinit_dma_addr(struct gdc_settings *gs) +static void meson_gdc_deinit_dma_addr(struct mgdc_fh_s *fh) { struct gdc_dma_cfg *dma_cfg = NULL; - struct gdc_config *gc = NULL; - struct mgdc_fh_s *fh = NULL; + struct gdc_cmd_s *gdc_cmd = &fh->gdc_cmd; + struct gdc_config_s *gc = &gdc_cmd->gdc_config; - if (gs == NULL || gs->fh == NULL) { - LOG(LOG_ERR, "Error input param\n"); + if (fh == NULL) { + gdc_log(LOG_ERR, "Error input param\n"); return; } - gc = &gs->gdc_config; - fh = gs->fh; - switch (gc->format) { case NV12: dma_cfg = &fh->y_dma_cfg; @@ -478,169 +474,410 @@ static void meson_gdc_deinit_dma_addr(struct gdc_settings *gs) meson_gdc_dma_unmap(dma_cfg); break; default: - LOG(LOG_ERR, "Error image format"); + gdc_log(LOG_ERR, "Error image format"); break; } } +static int gdc_buffer_alloc(struct gdc_dmabuf_req_s *gdc_req_buf) +{ + struct device *dev; + + dev = &(gdc_manager.gdc_dev->pdev->dev); + return gdc_dma_buffer_alloc(gdc_manager.buffer, + dev, gdc_req_buf); +} + +static int gdc_buffer_export(struct gdc_dmabuf_exp_s *gdc_exp_buf) +{ + return gdc_dma_buffer_export(gdc_manager.buffer, gdc_exp_buf); +} + +static int gdc_buffer_free(int index) +{ + return gdc_dma_buffer_free(gdc_manager.buffer, index); + +} + +static void gdc_buffer_dma_flush(int dma_fd) +{ + struct device *dev; + + dev = &(gdc_manager.gdc_dev->pdev->dev); + gdc_dma_buffer_dma_flush(dev, dma_fd); +} + +static void gdc_buffer_cache_flush(int dma_fd) +{ + struct device *dev; + + dev = &(gdc_manager.gdc_dev->pdev->dev); + gdc_dma_buffer_cache_flush(dev, dma_fd); +} + +static long gdc_process_input_dma_info(struct mgdc_fh_s *fh, + struct gdc_settings_ex *gs_ex) +{ + long ret = -1; + unsigned long addr; + struct aml_dma_cfg cfg; + struct gdc_cmd_s *gdc_cmd = &fh->gdc_cmd; + struct gdc_config_s *gc = &gdc_cmd->gdc_config; + + if (fh == NULL || gs_ex == NULL) { + gdc_log(LOG_ERR, "Error input param\n"); + return -EINVAL; + } + + switch (gc->format) { + case NV12: + if (gs_ex->input_buffer.plane_number == 1) { + cfg.fd = gs_ex->input_buffer.y_base_fd; + cfg.dev = &fh->gdev->pdev->dev; + cfg.dir = DMA_TO_DEVICE; + ret = gdc_dma_buffer_get_phys(&cfg, &addr); + if (ret < 0) { + gdc_log(LOG_ERR, + "dma import input fd %d failed\n", + gs_ex->input_buffer.y_base_fd); + return -EINVAL; + } + ret = meson_gdc_set_input_addr(addr, gdc_cmd); + if (ret != 0) { + gdc_log(LOG_ERR, "set input addr failed\n"); + return -EINVAL; + } + gdc_log(LOG_INFO, "1 plane get input addr=%x\n", + gdc_cmd->y_base_addr); + } else if (gs_ex->input_buffer.plane_number == 2) { + cfg.fd = gs_ex->input_buffer.y_base_fd; + cfg.dev = &fh->gdev->pdev->dev; + cfg.dir = DMA_TO_DEVICE; + ret = gdc_dma_buffer_get_phys(&cfg, &addr); + if (ret < 0) { + gdc_log(LOG_ERR, + "dma import input fd %d failed\n", + gs_ex->input_buffer.y_base_fd); + return -EINVAL; + } + gdc_cmd->y_base_addr = addr; + + cfg.fd = gs_ex->input_buffer.uv_base_fd; + cfg.dev = &fh->gdev->pdev->dev; + cfg.dir = DMA_TO_DEVICE; + ret = gdc_dma_buffer_get_phys(&cfg, &addr); + if (ret < 0) { + gdc_log(LOG_ERR, + "dma import input fd %d failed\n", + gs_ex->input_buffer.uv_base_fd); + return -EINVAL; + } + gdc_cmd->uv_base_addr = addr; + gdc_log(LOG_INFO, "2 plane get input addr=%x\n", + gdc_cmd->y_base_addr); + gdc_log(LOG_INFO, "2 plane get input addr=%x\n", + gdc_cmd->uv_base_addr); + } + break; + case Y_GREY: + cfg.fd = gs_ex->input_buffer.y_base_fd; + cfg.dev = &(fh->gdev->pdev->dev); + cfg.dir = DMA_TO_DEVICE; + ret = gdc_dma_buffer_get_phys(&cfg, &addr); + if (ret < 0) { + gdc_log(LOG_ERR, + "dma import input fd %d failed\n", + gs_ex->input_buffer.shared_fd); + return -EINVAL; + } + gdc_cmd->y_base_addr = addr; + gdc_cmd->uv_base_addr = 0; + break; + default: + gdc_log(LOG_ERR, "Error image format"); + break; + } + return 0; +} + +static long gdc_process_ex_info(struct mgdc_fh_s *fh, + struct gdc_settings_ex *gs_ex) +{ + long ret; + unsigned long addr = 0; + size_t len; + struct aml_dma_cfg cfg; + struct gdc_cmd_s *gdc_cmd = &fh->gdc_cmd; + + if (fh == NULL || gs_ex == NULL) { + gdc_log(LOG_ERR, "Error input param\n"); + return -EINVAL; + } + memcpy(&(gdc_cmd->gdc_config), &(gs_ex->gdc_config), + sizeof(struct gdc_config_s)); + gdc_cmd->fh = fh; + if (gs_ex->output_buffer.mem_alloc_type == AML_GDC_MEM_ION) { + /* ion alloc */ + ret = meson_ion_share_fd_to_phys(fh->ion_client, + gs_ex->output_buffer.shared_fd, + (ion_phys_addr_t *)&addr, &len); + if (ret < 0) { + gdc_log(LOG_ERR, "ion import out fd %d failed\n", + gs_ex->output_buffer.shared_fd); + return -EINVAL; + } + } else if (gs_ex->output_buffer.mem_alloc_type == AML_GDC_MEM_DMABUF) { + /* dma alloc */ + cfg.fd = gs_ex->output_buffer.y_base_fd; + cfg.dev = &(gdc_manager.gdc_dev->pdev->dev); + cfg.dir = DMA_FROM_DEVICE; + ret = gdc_dma_buffer_get_phys(&cfg, &addr); + if (ret < 0) { + gdc_log(LOG_ERR, "dma import out fd %d failed\n", + gs_ex->output_buffer.y_base_fd); + return -EINVAL; + } + + } + gdc_log(LOG_INFO, "%s, output addr=%lx\n", __func__, addr); + gdc_cmd->base_gdc = 0; + gdc_cmd->buffer_addr = addr; + gdc_cmd->current_addr = gdc_cmd->buffer_addr; + if (gs_ex->config_buffer.mem_alloc_type == AML_GDC_MEM_ION) { + /* ion alloc */ + ret = meson_ion_share_fd_to_phys(fh->ion_client, + gs_ex->config_buffer.shared_fd, + (ion_phys_addr_t *)&addr, &len); + if (ret < 0) { + gdc_log(LOG_ERR, "ion import config fd %d failed\n", + gs_ex->config_buffer.shared_fd); + return -EINVAL; + } + } else if (gs_ex->config_buffer.mem_alloc_type == AML_GDC_MEM_DMABUF) { + /* dma alloc */ + cfg.fd = gs_ex->config_buffer.y_base_fd; + cfg.dev = &(gdc_manager.gdc_dev->pdev->dev); + cfg.dir = DMA_TO_DEVICE; + ret = gdc_dma_buffer_get_phys(&cfg, &addr); + if (ret < 0) { + gdc_log(LOG_ERR, "dma import config fd %d failed\n", + gs_ex->config_buffer.shared_fd); + return -EINVAL; + } + } + gdc_cmd->gdc_config.config_addr = addr; + gdc_log(LOG_INFO, "%s, config addr=%lx\n", __func__, addr); + + if (gs_ex->input_buffer.mem_alloc_type == AML_GDC_MEM_ION) { + /* ion alloc */ + ret = meson_ion_share_fd_to_phys(fh->ion_client, + gs_ex->input_buffer.shared_fd, + (ion_phys_addr_t *)&addr, &len); + if (ret < 0) { + gdc_log(LOG_ERR, "ion import input fd %d failed\n", + gs_ex->input_buffer.shared_fd); + return -EINVAL; + } + ret = meson_gdc_set_input_addr(addr, gdc_cmd); + if (ret != 0) { + gdc_log(LOG_ERR, "set input addr failed\n"); + return -EINVAL; + } + } else if (gs_ex->input_buffer.mem_alloc_type == AML_GDC_MEM_DMABUF) { + /* dma alloc */ + gdc_process_input_dma_info(fh, gs_ex); + } + gdc_log(LOG_INFO, "%s, input addr=%x\n", + __func__, fh->gdc_cmd.y_base_addr); + mutex_lock(&fh->gdev->d_mutext); + #if 1 + if (gs_ex->config_buffer.mem_alloc_type == AML_GDC_MEM_DMABUF) + gdc_buffer_dma_flush(gs_ex->config_buffer.shared_fd); + #endif + ret = gdc_run(gdc_cmd); + if (ret < 0) + gdc_log(LOG_ERR, "gdc process failed ret = %ld\n", ret); + + ret = wait_for_completion_timeout(&fh->gdev->d_com, + msecs_to_jiffies(40)); + if (ret == 0) + gdc_log(LOG_ERR, "gdc timeout\n"); + + gdc_stop(gdc_cmd); + #if 0 + if (gs_ex->output_buffer.mem_alloc_type == AML_GDC_MEM_DMABUF) + gdc_buffer_cache_flush(gs_ex->output_buffer.shared_fd); + #endif + mutex_unlock(&fh->gdev->d_mutext); + return 0; +} + static long meson_gdc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - long ret = 0; + long ret = -1; size_t len; struct mgdc_fh_s *fh = file->private_data; - struct gdc_settings *gs = &fh->gs; - struct gdc_config *gc = &gs->gdc_config; + struct gdc_settings gs; + struct gdc_cmd_s *gdc_cmd = &fh->gdc_cmd; + struct gdc_config_s *gc = &gdc_cmd->gdc_config; struct gdc_buf_cfg buf_cfg; struct page *cma_pages = NULL; + struct gdc_settings_ex gs_ex; + struct gdc_dmabuf_req_s gdc_req_buf; + struct gdc_dmabuf_exp_s gdc_exp_buf; ion_phys_addr_t addr; + int index, dma_fd; void __user *argp = (void __user *)arg; switch (cmd) { case GDC_PROCESS: - ret = copy_from_user(gs, argp, sizeof(*gs)); + ret = copy_from_user(&gs, argp, sizeof(gs)); if (ret < 0) { - LOG(LOG_ERR, "copy from user failed\n"); + gdc_log(LOG_ERR, "copy from user failed\n"); return -EINVAL; } - LOG(LOG_DEBUG, "sizeof(gs)=%zu, magic=%d\n", - sizeof(*gs), gs->magic); + gdc_log(LOG_DEBUG, "sizeof(gs)=%zu, magic=%d\n", + sizeof(gs), gs.magic); //configure gdc config, buffer address and resolution ret = meson_ion_share_fd_to_phys(fh->ion_client, - gs->out_fd, &addr, &len); + gs.out_fd, &addr, &len); if (ret < 0) { - LOG(LOG_ERR, "import out fd %d failed\n", gs->out_fd); + gdc_log(LOG_ERR, + "import out fd %d failed\n", gs.out_fd); return -EINVAL; } + memcpy(&gdc_cmd->gdc_config, &gs.gdc_config, + sizeof(struct gdc_config_s)); + gdc_cmd->buffer_addr = addr; + gdc_cmd->buffer_size = len; - gs->buffer_addr = addr; - gs->buffer_size = len; - - gs->base_gdc = 0; - gs->current_addr = gs->buffer_addr; + gdc_cmd->base_gdc = 0; + gdc_cmd->current_addr = gdc_cmd->buffer_addr; ret = meson_ion_share_fd_to_phys(fh->ion_client, gc->config_addr, &addr, &len); if (ret < 0) { - LOG(LOG_ERR, "import config fd failed\n"); + gdc_log(LOG_ERR, "import config fd failed\n"); return -EINVAL; } gc->config_addr = addr; ret = meson_ion_share_fd_to_phys(fh->ion_client, - gs->in_fd, &addr, &len); + gs.in_fd, &addr, &len); if (ret < 0) { - LOG(LOG_ERR, "import in fd %d failed\n", gs->in_fd); + gdc_log(LOG_ERR, "import in fd %d failed\n", gs.in_fd); return -EINVAL; } - ret = meson_gdc_set_input_addr(addr, gs); + ret = meson_gdc_set_input_addr(addr, gdc_cmd); if (ret != 0) { - LOG(LOG_ERR, "set input addr failed\n"); + gdc_log(LOG_ERR, "set input addr failed\n"); return -EINVAL; } - gs->fh = fh; - + gdc_cmd->fh = fh; mutex_lock(&fh->gdev->d_mutext); - ret = gdc_run(gs); + ret = gdc_run(gdc_cmd); if (ret < 0) - LOG(LOG_ERR, "gdc process ret = %ld\n", ret); + gdc_log(LOG_ERR, "gdc process ret = %ld\n", ret); ret = wait_for_completion_timeout(&fh->gdev->d_com, msecs_to_jiffies(40)); if (ret == 0) - LOG(LOG_ERR, "gdc timeout\n"); + gdc_log(LOG_ERR, "gdc timeout\n"); - gdc_stop(gs); + gdc_stop(gdc_cmd); mutex_unlock(&fh->gdev->d_mutext); break; case GDC_RUN: - ret = copy_from_user(gs, argp, sizeof(*gs)); + ret = copy_from_user(&gs, argp, sizeof(gs)); if (ret < 0) - LOG(LOG_ERR, "copy from user failed\n"); + gdc_log(LOG_ERR, "copy from user failed\n"); - gs->buffer_addr = fh->o_paddr; - gs->buffer_size = fh->o_len; + memcpy(&gdc_cmd->gdc_config, &gs.gdc_config, + sizeof(struct gdc_config_s)); + gdc_cmd->buffer_addr = fh->o_paddr; + gdc_cmd->buffer_size = fh->o_len; - gs->base_gdc = 0; - gs->current_addr = gs->buffer_addr; + gdc_cmd->base_gdc = 0; + gdc_cmd->current_addr = gdc_cmd->buffer_addr; gc->config_addr = fh->c_paddr; - ret = meson_gdc_set_input_addr(fh->i_paddr, gs); + ret = meson_gdc_set_input_addr(fh->i_paddr, gdc_cmd); if (ret != 0) { - LOG(LOG_ERR, "set input addr failed\n"); + gdc_log(LOG_ERR, "set input addr failed\n"); return -EINVAL; } - gs->fh = fh; - + gdc_cmd->fh = fh; mutex_lock(&fh->gdev->d_mutext); meson_gdc_dma_flush(&fh->gdev->pdev->dev, fh->i_paddr, fh->i_len); meson_gdc_dma_flush(&fh->gdev->pdev->dev, fh->c_paddr, fh->c_len); - ret = gdc_run(gs); + ret = gdc_run(gdc_cmd); if (ret < 0) - LOG(LOG_ERR, "gdc process failed ret = %ld\n", ret); + gdc_log(LOG_ERR, "gdc process failed ret = %ld\n", ret); ret = wait_for_completion_timeout(&fh->gdev->d_com, msecs_to_jiffies(40)); if (ret == 0) - LOG(LOG_ERR, "gdc timeout\n"); + gdc_log(LOG_ERR, "gdc timeout\n"); - gdc_stop(gs); + gdc_stop(gdc_cmd); meson_gdc_cache_flush(&fh->gdev->pdev->dev, fh->o_paddr, fh->o_len); mutex_unlock(&fh->gdev->d_mutext); break; case GDC_HANDLE: - ret = copy_from_user(gs, argp, sizeof(*gs)); + ret = copy_from_user(&gs, argp, sizeof(gs)); if (ret < 0) - LOG(LOG_ERR, "copy from user failed\n"); + gdc_log(LOG_ERR, "copy from user failed\n"); - gs->buffer_addr = fh->o_paddr; - gs->buffer_size = fh->o_len; + memcpy(&gdc_cmd->gdc_config, &gs.gdc_config, + sizeof(struct gdc_config_s)); + gdc_cmd->buffer_addr = fh->o_paddr; + gdc_cmd->buffer_size = fh->o_len; - gs->base_gdc = 0; - gs->current_addr = gs->buffer_addr; + gdc_cmd->base_gdc = 0; + gdc_cmd->current_addr = gdc_cmd->buffer_addr; gc->config_addr = fh->c_paddr; - gs->fh = fh; - + gdc_cmd->fh = fh; mutex_lock(&fh->gdev->d_mutext); - ret = meson_gdc_init_dma_addr(gs); + ret = meson_gdc_init_dma_addr(fh, &gs); if (ret != 0) { mutex_unlock(&fh->gdev->d_mutext); - LOG(LOG_ERR, "Failed to init dma addr"); + gdc_log(LOG_ERR, "Failed to init dma addr"); return ret; } meson_gdc_dma_flush(&fh->gdev->pdev->dev, fh->c_paddr, fh->c_len); - ret = gdc_run(gs); + ret = gdc_run(gdc_cmd); if (ret < 0) - LOG(LOG_ERR, "gdc process failed ret = %ld\n", ret); + gdc_log(LOG_ERR, "gdc process failed ret = %ld\n", ret); ret = wait_for_completion_timeout(&fh->gdev->d_com, msecs_to_jiffies(40)); if (ret == 0) - LOG(LOG_ERR, "gdc timeout\n"); + gdc_log(LOG_ERR, "gdc timeout\n"); - gdc_stop(gs); + gdc_stop(gdc_cmd); meson_gdc_cache_flush(&fh->gdev->pdev->dev, fh->o_paddr, fh->o_len); - meson_gdc_deinit_dma_addr(gs); + meson_gdc_deinit_dma_addr(fh); mutex_unlock(&fh->gdev->d_mutext); break; case GDC_REQUEST_BUFF: ret = copy_from_user(&buf_cfg, argp, sizeof(buf_cfg)); if (ret < 0 || buf_cfg.type >= GDC_BUFF_TYPE_MAX) { - LOG(LOG_ERR, "Error user param\n"); + gdc_log(LOG_ERR, "Error user param\n"); return ret; } @@ -656,17 +893,77 @@ static long meson_gdc_ioctl(struct file *file, unsigned int cmd, &fh->gdev->pdev->dev, cma_pages, buf_cfg.len >> PAGE_SHIFT); - LOG(LOG_ERR, "Failed to set buff\n"); + gdc_log(LOG_ERR, "Failed to set buff\n"); return ret; } } else { - LOG(LOG_ERR, "Failed to alloc dma buff\n"); + gdc_log(LOG_ERR, "Failed to alloc dma buff\n"); return -ENOMEM; } break; + case GDC_PROCESS_EX: + ret = copy_from_user(&gs_ex, argp, sizeof(gs_ex)); + if (ret < 0) + gdc_log(LOG_ERR, "copy from user failed\n"); + memcpy(&gdc_cmd->gdc_config, &gs_ex.gdc_config, + sizeof(struct gdc_config_s)); + gdc_process_ex_info(fh, &gs_ex); + break; + case GDC_REQUEST_DMA_BUFF: + ret = copy_from_user(&gdc_req_buf, argp, + sizeof(struct gdc_dmabuf_req_s)); + if (ret < 0) { + pr_err("Error user param\n"); + return -EINVAL; + } + ret = gdc_buffer_alloc(&gdc_req_buf); + if (ret == 0) + ret = copy_to_user(argp, &gdc_req_buf, + sizeof(struct gdc_dmabuf_req_s)); + break; + case GDC_EXP_DMA_BUFF: + ret = copy_from_user(&gdc_exp_buf, argp, + sizeof(struct gdc_dmabuf_exp_s)); + if (ret < 0) { + pr_err("Error user param\n"); + return -EINVAL; + } + ret = gdc_buffer_export(&gdc_exp_buf); + if (ret == 0) + ret = copy_to_user(argp, &gdc_exp_buf, + sizeof(struct gdc_dmabuf_exp_s)); + break; + case GDC_FREE_DMA_BUFF: + ret = copy_from_user(&index, argp, + sizeof(int)); + if (ret < 0) { + pr_err("Error user param\n"); + return -EINVAL; + } + ret = gdc_buffer_free(index); + break; + case GDC_SYNC_DEVICE: + ret = copy_from_user(&dma_fd, argp, + sizeof(int)); + if (ret < 0) { + pr_err("Error user param\n"); + return -EINVAL; + } + gdc_buffer_dma_flush(dma_fd); + break; + case GDC_SYNC_CPU: + ret = copy_from_user(&dma_fd, argp, + sizeof(int)); + if (ret < 0) { + pr_err("Error user param\n"); + return -EINVAL; + } + gdc_buffer_cache_flush(dma_fd); + break; default: - LOG(LOG_ERR, "unsupported cmd 0x%x\n", cmd); + gdc_log(LOG_ERR, "unsupported cmd 0x%x\n", cmd); + return -EINVAL; break; } @@ -685,28 +982,28 @@ static int meson_gdc_mmap(struct file *file_p, switch (fh->mmap_type) { case INPUT_BUFF_TYPE: ret = remap_pfn_range(vma, vma->vm_start, - fh->i_paddr >> PAGE_SHIFT, - buf_len, vma->vm_page_prot); - if (ret != 0) - LOG(LOG_ERR, "Failed to mmap input buffer\n"); + fh->i_paddr >> PAGE_SHIFT, + buf_len, vma->vm_page_prot); + if (ret != 0) + gdc_log(LOG_ERR, "Failed to mmap input buffer\n"); break; case OUTPUT_BUFF_TYPE: - ret = remap_pfn_range(vma, vma->vm_start, - fh->o_paddr >> PAGE_SHIFT, - buf_len, vma->vm_page_prot); - if (ret != 0) - LOG(LOG_ERR, "Failed to mmap input buffer\n"); + ret = remap_pfn_range(vma, vma->vm_start, + fh->o_paddr >> PAGE_SHIFT, + buf_len, vma->vm_page_prot); + if (ret != 0) + gdc_log(LOG_ERR, "Failed to mmap input buffer\n"); break; case CONFIG_BUFF_TYPE: - ret = remap_pfn_range(vma, vma->vm_start, - fh->c_paddr >> PAGE_SHIFT, - buf_len, vma->vm_page_prot); - if (ret != 0) - LOG(LOG_ERR, "Failed to mmap input buffer\n"); + ret = remap_pfn_range(vma, vma->vm_start, + fh->c_paddr >> PAGE_SHIFT, + buf_len, vma->vm_page_prot); + if (ret != 0) + gdc_log(LOG_ERR, "Failed to mmap input buffer\n"); break; default: - LOG(LOG_ERR, "Error mmap type:0x%x\n", fh->mmap_type); + gdc_log(LOG_ERR, "Error mmap type:0x%x\n", fh->mmap_type); break; } @@ -746,7 +1043,7 @@ static ssize_t gdc_reg_show(struct device *dev, static ssize_t gdc_reg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - LOG(LOG_DEBUG, "%s, %d\n", __func__, __LINE__); + gdc_log(LOG_DEBUG, "%s, %d\n", __func__, __LINE__); return len; } static DEVICE_ATTR(gdc_reg, 0554, gdc_reg_show, gdc_reg_store); @@ -754,19 +1051,43 @@ static DEVICE_ATTR(gdc_reg, 0554, gdc_reg_show, gdc_reg_store); static ssize_t firmware1_show(struct device *dev, struct device_attribute *attr, char *buf) { - LOG(LOG_DEBUG, "%s, %d\n", __func__, __LINE__); + gdc_log(LOG_DEBUG, "%s, %d\n", __func__, __LINE__); return 1; } static ssize_t firmware1_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - LOG(LOG_DEBUG, "%s, %d\n", __func__, __LINE__); + gdc_log(LOG_DEBUG, "%s, %d\n", __func__, __LINE__); //gdc_fw_init(); return 1; } static DEVICE_ATTR(firmware1, 0664, firmware1_show, firmware1_store); +static ssize_t loglevel_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + + len += sprintf(buf+len, "%d\n", gdc_log_level); + return len; +} + +static ssize_t loglevel_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + pr_info("log_level: %d->%d\n", gdc_log_level, res); + gdc_log_level = res; + + return len; +} + +static DEVICE_ATTR(loglevel, 0664, loglevel_show, loglevel_store); + irqreturn_t gdc_interrupt_handler(int irq, void *param) { struct meson_gdc_dev_t *gdc_dev = param; @@ -789,34 +1110,34 @@ static int gdc_platform_probe(struct platform_device *pdev) gdc_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!gdc_res) { - LOG(LOG_ERR, "Error, no IORESOURCE_MEM DT!\n"); + gdc_log(LOG_ERR, "Error, no IORESOURCE_MEM DT!\n"); return -ENOMEM; } if (init_gdc_io(pdev->dev.of_node) != 0) { - LOG(LOG_ERR, "Error on mapping gdc memory!\n"); + gdc_log(LOG_ERR, "Error on mapping gdc memory!\n"); return -ENOMEM; } of_reserved_mem_device_init(&(pdev->dev)); - device_create_file(&pdev->dev, &dev_attr_gdc_reg); - device_create_file(&pdev->dev, &dev_attr_firmware1); - gdc_dev = devm_kzalloc(&pdev->dev, sizeof(*gdc_dev), GFP_KERNEL); if (gdc_dev == NULL) { - LOG(LOG_DEBUG, "devm alloc gdc dev failed\n"); + gdc_log(LOG_DEBUG, "devm alloc gdc dev failed\n"); return -ENOMEM; } gdc_dev->pdev = pdev; + gdc_dev->misc_dev.minor = meson_gdc_dev.minor; + gdc_dev->misc_dev.name = meson_gdc_dev.name; + gdc_dev->misc_dev.fops = meson_gdc_dev.fops; spin_lock_init(&gdc_dev->slock); gdc_dev->irq = platform_get_irq(pdev, 0); if (gdc_dev->irq < 0) { - LOG(LOG_DEBUG, "cannot find irq for gdc\n"); + gdc_log(LOG_DEBUG, "cannot find irq for gdc\n"); return -EINVAL; } @@ -831,9 +1152,9 @@ static int gdc_platform_probe(struct platform_device *pdev) iowrite32((3<<25)|(1<<24)|(0<<16)|(3<<9)|(1<<8)|(0<<0), clk_cntl); pd_cntl = of_iomap(pdev->dev.of_node, 2); reg_value = ioread32(pd_cntl); - LOG(LOG_DEBUG, "pd_cntl=%x\n", reg_value); + gdc_log(LOG_DEBUG, "pd_cntl=%x\n", reg_value); reg_value = reg_value & (~(3<<18)); - LOG(LOG_DEBUG, "pd_cntl=%x\n", reg_value); + gdc_log(LOG_DEBUG, "pd_cntl=%x\n", reg_value); iowrite32(reg_value, pd_cntl); #endif @@ -844,18 +1165,39 @@ static int gdc_platform_probe(struct platform_device *pdev) gdc_interrupt_handler, IRQF_SHARED, "gdc", gdc_dev); if (rc != 0) - LOG(LOG_ERR, "cannot create irq func gdc\n"); - - g_gdc_dev = gdc_dev; - - return misc_register(&meson_gdc_dev); + gdc_log(LOG_ERR, "cannot create irq func gdc\n"); + + gdc_manager.buffer = gdc_dma_buffer_create(); + gdc_manager.gdc_dev = gdc_dev; + rc = misc_register(&gdc_dev->misc_dev); + if (rc < 0) { + dev_err(&pdev->dev, + "misc_register() for minor %d failed\n", + gdc_dev->misc_dev.minor); + } + device_create_file(gdc_dev->misc_dev.this_device, + &dev_attr_gdc_reg); + device_create_file(gdc_dev->misc_dev.this_device, + &dev_attr_firmware1); + device_create_file(gdc_dev->misc_dev.this_device, + &dev_attr_loglevel); + + platform_set_drvdata(pdev, gdc_dev); + return rc; } static int gdc_platform_remove(struct platform_device *pdev) { - device_remove_file(&pdev->dev, &dev_attr_gdc_reg); - device_remove_file(&pdev->dev, &dev_attr_firmware1); + device_remove_file(meson_gdc_dev.this_device, + &dev_attr_gdc_reg); + device_remove_file(meson_gdc_dev.this_device, + &dev_attr_firmware1); + device_remove_file(meson_gdc_dev.this_device, + &dev_attr_loglevel); + + gdc_dma_buffer_destroy(gdc_manager.buffer); + gdc_manager.gdc_dev = NULL; misc_deregister(&meson_gdc_dev); return 0; diff --git a/drivers/amlogic/media/gdc/inc/api/gdc_api.h b/drivers/amlogic/media/gdc/inc/api/gdc_api.h index 2f3fb8f..942bd40 100644 --- a/drivers/amlogic/media/gdc/inc/api/gdc_api.h +++ b/drivers/amlogic/media/gdc/inc/api/gdc_api.h @@ -21,13 +21,19 @@ #include #include +enum gdc_memtype_s { + AML_GDC_MEM_ION, + AML_GDC_MEM_DMABUF, + AML_GDC_MEM_INVALID, +}; + struct gdc_buf_cfg { uint32_t type; unsigned long len; }; // each configuration addresses and size -struct gdc_config { +struct gdc_config_s { uint32_t format; uint32_t config_addr; //gdc config address uint32_t config_size; //gdc config size in 32bit @@ -41,13 +47,27 @@ struct gdc_config { uint32_t output_c_stride; //gdc output uv stride }; +struct gdc_buffer_info { + unsigned int mem_alloc_type; + unsigned int plane_number; + union { + unsigned int y_base_fd; + unsigned int shared_fd; + }; + union { + unsigned int uv_base_fd; + unsigned int u_base_fd; + }; + unsigned int v_base_fd; +}; + // overall gdc settings and state struct gdc_settings { uint32_t magic; //writing/reading to gdc base address, currently not read by api uint32_t base_gdc; //array of gdc configuration and sizes - struct gdc_config gdc_config; + struct gdc_config_s gdc_config; //update this index for new config //int gdc_config_total; //start memory to write gdc output framse @@ -88,6 +108,28 @@ struct gdc_settings { int32_t v_base_fd; }; +struct gdc_settings_ex { + uint32_t magic; + struct gdc_config_s gdc_config; + struct gdc_buffer_info input_buffer; + struct gdc_buffer_info config_buffer; + struct gdc_buffer_info output_buffer; +}; + +/* for gdc dma buf define */ +struct gdc_dmabuf_req_s { + int index; + unsigned int len; + unsigned int dma_dir; +}; + +struct gdc_dmabuf_exp_s { + int index; + unsigned int flags; + int fd; +}; +/* end of gdc dma buffer define */ + #define GDC_IOC_MAGIC 'G' #define GDC_PROCESS _IOW(GDC_IOC_MAGIC, 0x00, struct gdc_settings) #define GDC_PROCESS_NO_BLOCK _IOW(GDC_IOC_MAGIC, 0x01, struct gdc_settings) @@ -95,6 +137,14 @@ struct gdc_settings { #define GDC_REQUEST_BUFF _IOW(GDC_IOC_MAGIC, 0x03, struct gdc_settings) #define GDC_HANDLE _IOW(GDC_IOC_MAGIC, 0x04, struct gdc_settings) +#define GDC_PROCESS_EX _IOW(GDC_IOC_MAGIC, 0x05, struct gdc_settings_ex) +#define GDC_REQUEST_DMA_BUFF _IOW(GDC_IOC_MAGIC, 0x06, struct gdc_dmabuf_req_s) +#define GDC_EXP_DMA_BUFF _IOW(GDC_IOC_MAGIC, 0x07, struct gdc_dmabuf_exp_s) +#define GDC_FREE_DMA_BUFF _IOW(GDC_IOC_MAGIC, 0x08, int) +#define GDC_SYNC_DEVICE _IOW(GDC_IOC_MAGIC, 0x09, int) +#define GDC_SYNC_CPU _IOW(GDC_IOC_MAGIC, 0x0a, int) + + enum { INPUT_BUFF_TYPE = 0x1000, OUTPUT_BUFF_TYPE, @@ -121,6 +171,40 @@ struct gdc_dma_cfg { enum dma_data_direction dir; }; +struct gdc_cmd_s { + //writing/reading to gdc base address, currently not read by api + uint32_t base_gdc; + //array of gdc configuration and sizes + struct gdc_config_s gdc_config; + //update this index for new config + //int gdc_config_total; + //start memory to write gdc output framse + uint32_t buffer_addr; + //size of memory output frames to determine + //if it is enough and can do multiple write points + uint32_t buffer_size; + //current output address of gdc + uint32_t current_addr; + //set when expecting an interrupt from gdc + int32_t is_waiting_gdc; + + //input address for y and u, v planes + uint32_t y_base_addr; + union { + uint32_t uv_base_addr; + uint32_t u_base_addr; + }; + uint32_t v_base_addr; + + //when inititialised this callback will be called + //to update frame buffer addresses and offsets + void (*get_frame_buffer)(uint32_t y_base_addr, + uint32_t uv_base_addr, + uint32_t y_line_offset, + uint32_t uv_line_offset); + void *fh; +}; + /** * Configure the output gdc configuration * @@ -128,30 +212,30 @@ struct gdc_dma_cfg { * * More than one gdc settings can be accessed by index to a gdc_config_t. * - * @param gdc_settings - overall gdc settings and state + * @param gdc_cmd_s - overall gdc settings and state * @param gdc_config_num - selects the current gdc config to be applied * * @return 0 - success * -1 - fail. */ -int gdc_init(struct gdc_settings *gdc_settings); +int gdc_init(struct gdc_cmd_s *gdc_cmd); /** * This function stops the gdc block * - * @param gdc_settings - overall gdc settings and state + * @param gdc_cmd_s - overall gdc settings and state * */ -void gdc_stop(struct gdc_settings *gdc_settings); +void gdc_stop(struct gdc_cmd_s *gdc_cmd); /** * This function starts the gdc block * * Writing 0->1 transition is necessary for trigger * - * @param gdc_settings - overall gdc settings and state + * @param gdc_cmd_s - overall gdc settings and state * */ -void gdc_start(struct gdc_settings *gdc_settings); +void gdc_start(struct gdc_cmd_s *gdc_cmd); /** * This function points gdc to @@ -160,7 +244,7 @@ void gdc_start(struct gdc_settings *gdc_settings); * * Shown inputs to GDC are Y and UV plane address and offsets * - * @param gdc_settings - overall gdc settings and state + * @param gdc_cmd_s - overall gdc settings and state * @param active_width - input width resolution * @param active_height - input height resolution * @param y_base_addr - input Y base address @@ -171,20 +255,20 @@ void gdc_start(struct gdc_settings *gdc_settings); * @return 0 - success * -1 - no interrupt from GDC. */ -int gdc_process(struct gdc_settings *gdc_settings, +int gdc_process(struct gdc_cmd_s *gdc_cmd, uint32_t y_base_addr, uint32_t uv_base_addr); -int gdc_process_yuv420p(struct gdc_settings *gdc_settings, +int gdc_process_yuv420p(struct gdc_cmd_s *gdc_cmd, uint32_t y_base_addr, uint32_t u_base_addr, uint32_t v_base_addr); -int gdc_process_y_grey(struct gdc_settings *gdc_settings, +int gdc_process_y_grey(struct gdc_cmd_s *gdc_cmd, uint32_t y_base_addr); -int gdc_process_yuv444p(struct gdc_settings *gdc_settings, +int gdc_process_yuv444p(struct gdc_cmd_s *gdc_cmd, uint32_t y_base_addr, uint32_t u_base_addr, uint32_t v_base_addr); -int gdc_process_rgb444p(struct gdc_settings *gdc_settings, +int gdc_process_rgb444p(struct gdc_cmd_s *gdc_cmd, uint32_t y_base_addr, uint32_t u_base_addr, uint32_t v_base_addr); @@ -198,12 +282,12 @@ int gdc_process_rgb444p(struct gdc_settings *gdc_settings, * * Y and UV plane address and offsets * - * @param gdc_settings - overall gdc settings and state + * @param gdc_cmd_s - overall gdc settings and state * * @return 0 - success * -1 - unexpected interrupt from GDC. */ -int gdc_get_frame(struct gdc_settings *gdc_settings); +int gdc_get_frame(struct gdc_cmd_s *gdc_cmd); /** * This function points gdc to its input resolution @@ -212,12 +296,12 @@ int gdc_get_frame(struct gdc_settings *gdc_settings); * * Shown inputs to GDC are Y and UV plane address and offsets * - * @param gdc_settings - overall gdc settings and state + * @param gdc_cmd_s - overall gdc settings and state * * @return 0 - success * -1 - no interrupt from GDC. */ -int gdc_run(struct gdc_settings *g); +int gdc_run(struct gdc_cmd_s *g); int32_t init_gdc_io(struct device_node *dn); diff --git a/drivers/amlogic/media/gdc/inc/gdc/gdc_config.h b/drivers/amlogic/media/gdc/inc/gdc/gdc_config.h index db8c9b7..9cab803 100644 --- a/drivers/amlogic/media/gdc/inc/gdc/gdc_config.h +++ b/drivers/amlogic/media/gdc/inc/gdc/gdc_config.h @@ -22,10 +22,17 @@ #include #include #include +#include #include "system_gdc_io.h" #include "gdc_api.h" -struct gdc_settings; +struct gdc_cmd_s; + +struct gdc_manager_s { + struct aml_dma_buffer *buffer; + struct meson_gdc_dev_t *gdc_dev; +}; + struct meson_gdc_dev_t { struct platform_device *pdev; void *reg_base; @@ -35,6 +42,7 @@ struct meson_gdc_dev_t { struct mutex d_mutext; struct completion d_com; int irq; + struct miscdevice misc_dev; }; struct mgdc_fh_s { @@ -43,7 +51,7 @@ struct mgdc_fh_s { struct meson_gdc_dev_t *gdev; char task_comm[32]; struct ion_client *ion_client; - struct gdc_settings gs; + struct gdc_cmd_s gdc_cmd; uint32_t mmap_type; dma_addr_t i_paddr; dma_addr_t o_paddr; diff --git a/drivers/amlogic/media/gdc/inc/sys/system_log.h b/drivers/amlogic/media/gdc/inc/sys/system_log.h index e9f0bc2..cae4ee0 100644 --- a/drivers/amlogic/media/gdc/inc/sys/system_log.h +++ b/drivers/amlogic/media/gdc/inc/sys/system_log.h @@ -20,36 +20,27 @@ //changeable logs #include -#define FW_LOG_LEVEL LOG_ERR +extern unsigned int gdc_log_level; enum log_level_e { - LOG_NOTHING, - LOG_EMERG, - LOG_ALERT, + LOG_NO_THING, LOG_CRIT, LOG_ERR, LOG_WARNING, - LOG_NOTICE, LOG_INFO, LOG_DEBUG, - LOG_IRQ, LOG_MAX }; -extern const char *const gdc_log_level[LOG_MAX]; - -#define FILE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) - #if 1 -#define LOG(level, fmt, arg...) \ +#define gdc_log(level, fmt, ...) \ do { \ - if ((level) <= FW_LOG_LEVEL) \ - pr_info("%s: %s(%d) %s: " fmt "\n",\ - FILE, __func__, __LINE__, \ - gdc_log_level[level], ## arg); \ + if (level <= gdc_log_level) \ + pr_info("%s: "fmt, __func__, ##__VA_ARGS__); \ } while (0) + #else -#define LOG(...) +#define gdc_log(...) #endif #endif // __SYSTEM_LOG_H__ diff --git a/drivers/amlogic/media/gdc/src/fw_lib/acamera_gdc.c b/drivers/amlogic/media/gdc/src/fw_lib/acamera_gdc.c index 83a988e..e86cff5 100644 --- a/drivers/amlogic/media/gdc/src/fw_lib/acamera_gdc.c +++ b/drivers/amlogic/media/gdc/src/fw_lib/acamera_gdc.c @@ -36,32 +36,32 @@ * * More than one gdc settings can be accessed by index to a gdc_config_t. * - * @param gdc_settings - overall gdc settings and state + * @param gdc_cmd - overall gdc settings and state * @param gdc_config_num - selects the current gdc config to be applied * * @return 0 - success * -1 - fail. */ -int gdc_init(struct gdc_settings *gdc_settings) +int gdc_init(struct gdc_cmd_s *gdc_cmd) { - gdc_settings->is_waiting_gdc = 0; - gdc_settings->current_addr = gdc_settings->buffer_addr; + gdc_cmd->is_waiting_gdc = 0; + gdc_cmd->current_addr = gdc_cmd->buffer_addr; - if ((gdc_settings->gdc_config.output_width == 0) - || (gdc_settings->gdc_config.output_height == 0)) { - LOG(LOG_ERR, "Wrong GDC output resolution.\n"); + if ((gdc_cmd->gdc_config.output_width == 0) + || (gdc_cmd->gdc_config.output_height == 0)) { + gdc_log(LOG_ERR, "Wrong GDC output resolution.\n"); return -1; } //stop gdc gdc_start_flag_write(0); //set the configuration address and size to the gdc block - gdc_config_addr_write(gdc_settings->gdc_config.config_addr); - gdc_config_size_write(gdc_settings->gdc_config.config_size); + gdc_config_addr_write(gdc_cmd->gdc_config.config_addr); + gdc_config_size_write(gdc_cmd->gdc_config.config_size); //set the gdc output resolution - gdc_dataout_width_write(gdc_settings->gdc_config.output_width); - gdc_dataout_height_write(gdc_settings->gdc_config.output_height); + gdc_dataout_width_write(gdc_cmd->gdc_config.output_width); + gdc_dataout_height_write(gdc_cmd->gdc_config.output_height); return 0; } @@ -69,12 +69,12 @@ int gdc_init(struct gdc_settings *gdc_settings) /** * This function stops the gdc block * - * @param gdc_settings - overall gdc settings and state + * @param gdc_cmd - overall gdc settings and state * */ -void gdc_stop(struct gdc_settings *gdc_settings) +void gdc_stop(struct gdc_cmd_s *gdc_cmd) { - gdc_settings->is_waiting_gdc = 0; + gdc_cmd->is_waiting_gdc = 0; gdc_start_flag_write(0); } @@ -83,14 +83,14 @@ void gdc_stop(struct gdc_settings *gdc_settings) * * Writing 0->1 transition is necessary for trigger * - * @param gdc_settings - overall gdc settings and state + * @param gdc_cmd - overall gdc settings and state * */ -void gdc_start(struct gdc_settings *gdc_settings) +void gdc_start(struct gdc_cmd_s *gdc_cmd) { gdc_start_flag_write(0); //do a stop for sync gdc_start_flag_write(1); - gdc_settings->is_waiting_gdc = 1; + gdc_cmd->is_waiting_gdc = 1; } /** @@ -100,7 +100,7 @@ void gdc_start(struct gdc_settings *gdc_settings) * * Shown inputs to GDC are Y and UV plane address and offsets * - * @param gdc_settings - overall gdc settings and state + * @param gdc_cmd - overall gdc settings and state * @param active_width - input width resolution * @param active_height - input height resolution * @param y_base_addr - input Y base address @@ -111,27 +111,27 @@ void gdc_start(struct gdc_settings *gdc_settings) * @return 0 - success * -1 - no interrupt from GDC. */ -int gdc_process(struct gdc_settings *gdc_settings, +int gdc_process(struct gdc_cmd_s *gdc_cmd, uint32_t y_base_addr, uint32_t uv_base_addr) { - uint32_t gdc_out_base_addr = gdc_settings->current_addr; - uint32_t input_width = gdc_settings->gdc_config.input_width; - uint32_t input_height = gdc_settings->gdc_config.input_height; - uint32_t output_height = gdc_settings->gdc_config.output_height; - uint32_t i_y_line_offset = gdc_settings->gdc_config.input_y_stride; - uint32_t i_uv_line_offset = gdc_settings->gdc_config.input_c_stride; - uint32_t o_y_line_offset = gdc_settings->gdc_config.output_y_stride; - uint32_t o_uv_line_offset = gdc_settings->gdc_config.output_c_stride; - - if (gdc_settings->is_waiting_gdc) { + uint32_t gdc_out_base_addr = gdc_cmd->current_addr; + uint32_t input_width = gdc_cmd->gdc_config.input_width; + uint32_t input_height = gdc_cmd->gdc_config.input_height; + uint32_t output_height = gdc_cmd->gdc_config.output_height; + uint32_t i_y_line_offset = gdc_cmd->gdc_config.input_y_stride; + uint32_t i_uv_line_offset = gdc_cmd->gdc_config.input_c_stride; + uint32_t o_y_line_offset = gdc_cmd->gdc_config.output_y_stride; + uint32_t o_uv_line_offset = gdc_cmd->gdc_config.output_c_stride; + + if (gdc_cmd->is_waiting_gdc) { gdc_start_flag_write(0); - LOG(LOG_CRIT, "No interrupt Still waiting...\n"); + gdc_log(LOG_CRIT, "No interrupt Still waiting...\n"); gdc_start_flag_write(1); return -1; } - LOG(LOG_DEBUG, "starting GDC process.\n"); + gdc_log(LOG_DEBUG, "starting GDC process.\n"); gdc_datain_width_write(input_width); gdc_datain_height_write(input_height); @@ -152,7 +152,7 @@ int gdc_process(struct gdc_settings *gdc_settings, gdc_data2out_addr_write(gdc_out_base_addr); gdc_data2out_line_offset_write(o_uv_line_offset); - gdc_start(gdc_settings); + gdc_start(gdc_cmd); return 0; } @@ -164,7 +164,7 @@ int gdc_process(struct gdc_settings *gdc_settings, * * Shown inputs to GDC are Y and UV plane address and offsets * - * @param gdc_settings - overall gdc settings and state + * @param gdc_cmd - overall gdc settings and state * @param active_width - input width resolution * @param active_height - input height resolution * @param y_base_addr - input Y base address @@ -175,27 +175,27 @@ int gdc_process(struct gdc_settings *gdc_settings, * @return 0 - success * -1 - no interrupt from GDC. */ -int gdc_process_yuv420p(struct gdc_settings *gdc_settings, +int gdc_process_yuv420p(struct gdc_cmd_s *gdc_cmd, uint32_t y_base_addr, uint32_t u_base_addr, uint32_t v_base_addr) { - struct gdc_config *gc = &gdc_settings->gdc_config; - uint32_t gdc_out_base_addr = gdc_settings->current_addr; + struct gdc_config_s *gc = &gdc_cmd->gdc_config; + uint32_t gdc_out_base_addr = gdc_cmd->current_addr; uint32_t input_width = gc->input_width; uint32_t input_height = gc->input_height; uint32_t input_stride = gc->input_y_stride; uint32_t input_u_stride = gc->input_c_stride; uint32_t input_v_stride = gc->input_c_stride; - LOG(LOG_DEBUG, "is_waiting_gdc=%d\n", gdc_settings->is_waiting_gdc); - if (gdc_settings->is_waiting_gdc) { + gdc_log(LOG_DEBUG, "is_waiting_gdc=%d\n", gdc_cmd->is_waiting_gdc); + if (gdc_cmd->is_waiting_gdc) { gdc_start_flag_write(0); - LOG(LOG_CRIT, "No interrupt Still waiting...\n"); + gdc_log(LOG_CRIT, "No interrupt Still waiting...\n"); gdc_start_flag_write(1); return -1; } ///// - LOG(LOG_DEBUG, "starting GDC process.\n"); + gdc_log(LOG_DEBUG, "starting GDC process.\n"); //already set in gdc_init //uint32_t output_width = gc->output_width; @@ -231,7 +231,7 @@ int gdc_process_yuv420p(struct gdc_settings *gdc_settings, gdc_out_base_addr += output_height * output_u_stride / 2; gdc_data3out_addr_write(gdc_out_base_addr); gdc_data3out_line_offset_write(output_v_stride); - gdc_start(gdc_settings); + gdc_start(gdc_cmd); return 0; } @@ -244,7 +244,7 @@ int gdc_process_yuv420p(struct gdc_settings *gdc_settings, * * Shown inputs to GDC are Y plane address and offsets * - * @param gdc_settings - overall gdc settings and state + * @param gdc_cmd - overall gdc settings and state * @param active_width - input width resolution * @param active_height - input height resolution * @param y_base_addr - input Y base address @@ -253,25 +253,25 @@ int gdc_process_yuv420p(struct gdc_settings *gdc_settings, * @return 0 - success * -1 - no interrupt from GDC. */ -int gdc_process_y_grey(struct gdc_settings *gdc_settings, +int gdc_process_y_grey(struct gdc_cmd_s *gdc_cmd, uint32_t y_base_addr) { - struct gdc_config *gc = &gdc_settings->gdc_config; - uint32_t gdc_out_base_addr = gdc_settings->current_addr; + struct gdc_config_s *gc = &gdc_cmd->gdc_config; + uint32_t gdc_out_base_addr = gdc_cmd->current_addr; uint32_t input_width = gc->input_width; uint32_t input_height = gc->input_height; uint32_t input_stride = gc->input_y_stride; uint32_t output_stride = gc->output_y_stride; - LOG(LOG_DEBUG, "is_waiting_gdc=%d\n", gdc_settings->is_waiting_gdc); - if (gdc_settings->is_waiting_gdc) { + gdc_log(LOG_DEBUG, "is_waiting_gdc=%d\n", gdc_cmd->is_waiting_gdc); + if (gdc_cmd->is_waiting_gdc) { gdc_start_flag_write(0); - LOG(LOG_CRIT, "No interrupt Still waiting...\n"); + gdc_log(LOG_CRIT, "No interrupt Still waiting...\n"); gdc_start_flag_write(1); return -1; } - LOG(LOG_DEBUG, "starting GDC process.\n"); + gdc_log(LOG_DEBUG, "starting GDC process.\n"); gdc_datain_width_write(input_width); gdc_datain_height_write(input_height); @@ -283,7 +283,7 @@ int gdc_process_y_grey(struct gdc_settings *gdc_settings, gdc_data1out_addr_write(gdc_out_base_addr); gdc_data1out_line_offset_write(output_stride); - gdc_start(gdc_settings); + gdc_start(gdc_cmd); return 0; } @@ -295,7 +295,7 @@ int gdc_process_y_grey(struct gdc_settings *gdc_settings, * * Shown inputs to GDC are Y and UV plane address and offsets * - * @param gdc_settings - overall gdc settings and state + * @param gdc_cmd - overall gdc settings and state * @param active_width - input width resolution * @param active_height - input height resolution * @param y_base_addr - input Y base address @@ -306,11 +306,11 @@ int gdc_process_y_grey(struct gdc_settings *gdc_settings, * @return 0 - success * -1 - no interrupt from GDC. */ -int gdc_process_yuv444p(struct gdc_settings *gdc_settings, +int gdc_process_yuv444p(struct gdc_cmd_s *gdc_cmd, uint32_t y_base_addr, uint32_t u_base_addr, uint32_t v_base_addr) { - struct gdc_config *gc = &gdc_settings->gdc_config; - uint32_t gdc_out_base_addr = gdc_settings->current_addr; + struct gdc_config_s *gc = &gdc_cmd->gdc_config; + uint32_t gdc_out_base_addr = gdc_cmd->current_addr; uint32_t input_width = gc->input_width; uint32_t input_height = gc->input_height; uint32_t input_stride = gc->input_y_stride; @@ -321,15 +321,15 @@ int gdc_process_yuv444p(struct gdc_settings *gdc_settings, uint32_t output_u_stride = gc->output_c_stride; uint32_t output_v_stride = gc->output_c_stride; - LOG(LOG_DEBUG, "is_waiting_gdc=%d\n", gdc_settings->is_waiting_gdc); - if (gdc_settings->is_waiting_gdc) { + gdc_log(LOG_DEBUG, "is_waiting_gdc=%d\n", gdc_cmd->is_waiting_gdc); + if (gdc_cmd->is_waiting_gdc) { gdc_start_flag_write(0); - LOG(LOG_CRIT, "No interrupt Still waiting...\n"); + gdc_log(LOG_CRIT, "No interrupt Still waiting...\n"); gdc_start_flag_write(1); return -1; } - LOG(LOG_DEBUG, "starting GDC process.\n"); + gdc_log(LOG_DEBUG, "starting GDC process.\n"); gdc_datain_width_write(input_width); gdc_datain_height_write(input_height); @@ -358,7 +358,7 @@ int gdc_process_yuv444p(struct gdc_settings *gdc_settings, gdc_out_base_addr += output_height * output_u_stride; gdc_data3out_addr_write(gdc_out_base_addr); gdc_data3out_line_offset_write(output_v_stride); - gdc_start(gdc_settings); + gdc_start(gdc_cmd); return 0; } @@ -370,7 +370,7 @@ int gdc_process_yuv444p(struct gdc_settings *gdc_settings, * * Shown inputs to GDC are R\G\B plane address and offsets * - * @param gdc_settings - overall gdc settings and state + * @param gdc_cmd - overall gdc settings and state * @param active_width - input width resolution * @param active_height - input height resolution * @param y_base_addr - input R base address @@ -383,11 +383,11 @@ int gdc_process_yuv444p(struct gdc_settings *gdc_settings, * @return 0 - success * -1 - no interrupt from GDC. */ -int gdc_process_rgb444p(struct gdc_settings *gdc_settings, +int gdc_process_rgb444p(struct gdc_cmd_s *gdc_cmd, uint32_t y_base_addr, uint32_t u_base_addr, uint32_t v_base_addr) { - struct gdc_config *gc = &gdc_settings->gdc_config; - uint32_t gdc_out_base_addr = gdc_settings->current_addr; + struct gdc_config_s *gc = &gdc_cmd->gdc_config; + uint32_t gdc_out_base_addr = gdc_cmd->current_addr; uint32_t input_width = gc->input_width; uint32_t input_height = gc->input_height; uint32_t input_stride = gc->input_y_stride; @@ -398,15 +398,15 @@ int gdc_process_rgb444p(struct gdc_settings *gdc_settings, uint32_t output_u_stride = gc->output_c_stride; uint32_t output_v_stride = gc->output_c_stride; - LOG(LOG_DEBUG, "is_waiting_gdc=%d\n", gdc_settings->is_waiting_gdc); - if (gdc_settings->is_waiting_gdc) { + gdc_log(LOG_DEBUG, "is_waiting_gdc=%d\n", gdc_cmd->is_waiting_gdc); + if (gdc_cmd->is_waiting_gdc) { gdc_start_flag_write(0); - LOG(LOG_CRIT, "No interrupt Still waiting...\n"); + gdc_log(LOG_CRIT, "No interrupt Still waiting...\n"); gdc_start_flag_write(1); return -1; } - LOG(LOG_DEBUG, "starting GDC process.\n"); + gdc_log(LOG_DEBUG, "starting GDC process.\n"); gdc_datain_width_write(input_width); gdc_datain_height_write(input_height); @@ -435,7 +435,7 @@ int gdc_process_rgb444p(struct gdc_settings *gdc_settings, gdc_out_base_addr += output_height * output_u_stride; gdc_data3out_addr_write(gdc_out_base_addr); gdc_data3out_line_offset_write(output_v_stride); - gdc_start(gdc_settings); + gdc_start(gdc_cmd); return 0; } @@ -449,21 +449,21 @@ int gdc_process_rgb444p(struct gdc_settings *gdc_settings, * * Y and UV plane address and offsets * - * @param gdc_settings - overall gdc settings and state + * @param gdc_cmd - overall gdc settings and state * * @return 0 - success * -1 - unexpected interrupt from GDC. */ -int gdc_get_frame(struct gdc_settings *gdc_settings) +int gdc_get_frame(struct gdc_cmd_s *gdc_cmd) { - struct mgdc_fh_s *fh = gdc_settings->fh; + struct mgdc_fh_s *fh = gdc_cmd->fh; uint32_t y; uint32_t y_offset; uint32_t uv; uint32_t uv_offset; - if (!gdc_settings->is_waiting_gdc) { - LOG(LOG_CRIT, "Unexpected interrupt from GDC.\n"); + if (!gdc_cmd->is_waiting_gdc) { + gdc_log(LOG_CRIT, "Unexpected interrupt from GDC.\n"); return -1; } //// @@ -471,17 +471,17 @@ int gdc_get_frame(struct gdc_settings *gdc_settings) wake_up_interruptible(&fh->irq_queue); //pass the frame buffer parameters if callback is available - if (gdc_settings->get_frame_buffer) { + if (gdc_cmd->get_frame_buffer) { y = gdc_data1out_addr_read(); y_offset = gdc_data1out_line_offset_read(); uv = gdc_data2out_addr_read(); uv_offset = gdc_data2out_line_offset_read(); - gdc_settings->get_frame_buffer(y, + gdc_cmd->get_frame_buffer(y, uv, y_offset, uv_offset); } //done of the current frame and stop gdc block - gdc_stop(gdc_settings); + gdc_stop(gdc_cmd); //spin_unlock_irqrestore(&gdev->slock, flags); return 0; } diff --git a/drivers/amlogic/media/gdc/src/platform/system_gdc_io.c b/drivers/amlogic/media/gdc/src/platform/system_gdc_io.c index 378789f..fcb09ab 100644 --- a/drivers/amlogic/media/gdc/src/platform/system_gdc_io.c +++ b/drivers/amlogic/media/gdc/src/platform/system_gdc_io.c @@ -30,7 +30,7 @@ int32_t init_gdc_io(struct device_node *dn) pr_info("reg base = %p\n", p_hw_base); if (!p_hw_base) { - LOG(LOG_DEBUG, "failed to map register, %p\n", p_hw_base); + gdc_log(LOG_DEBUG, "failed to map register, %p\n", p_hw_base); return -1; } @@ -39,28 +39,32 @@ int32_t init_gdc_io(struct device_node *dn) void close_gdc_io(struct device_node *dn) { - LOG(LOG_DEBUG, "IO functionality has been closed"); + gdc_log(LOG_DEBUG, "IO functionality has been closed"); } uint32_t system_gdc_read_32(uint32_t addr) { uint32_t result = 0; - if (p_hw_base == NULL) - LOG(LOG_ERR, "Failed to base address %d\n", addr); + if (p_hw_base == NULL) { + gdc_log(LOG_ERR, "Failed to base address %d\n", addr); + return 0; + } result = ioread32(p_hw_base + addr); - LOG(LOG_DEBUG, "r [0x%04x]= %08x\n", addr, result); + gdc_log(LOG_DEBUG, "r [0x%04x]= %08x\n", addr, result); return result; } void system_gdc_write_32(uint32_t addr, uint32_t data) { - if (p_hw_base == NULL) - LOG(LOG_ERR, "Failed to write %d to addr %d\n", data, addr); + if (p_hw_base == NULL) { + gdc_log(LOG_ERR, "Failed to write %d to addr %d\n", data, addr); + return; + } void *ptr = (void *)(p_hw_base + addr); iowrite32(data, ptr); - LOG(LOG_DEBUG, "w [0x%04x]= %08x\n", addr, data); + gdc_log(LOG_DEBUG, "w [0x%04x]= %08x\n", addr, data); } -- 2.7.4