mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
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 <pengcheng.chen@amlogic.com> Signed-off-by: Luan Yuan <luan.yuan@amlogic.com> Conflicts: MAINTAINERS
This commit is contained in:
@@ -14751,6 +14751,12 @@ M: Pengcheng Chen <pengcheng.chen@amlogic.com>
|
||||
F: drivers/amlogic/media/common/ge2d/ge2d_dmabuf.c
|
||||
F: drivers/amlogic/media/common/ge2d/ge2d_dmabuf.h
|
||||
|
||||
AMLOGIC GDC DRIVER
|
||||
M: Pengcheng Chen <pengcheng.chen@amlogic.com>
|
||||
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
|
||||
|
||||
AMLOGIC VIDEOSYNC
|
||||
M: Jintao Xu <jintao.xu@amlogic.com>
|
||||
F: drivers/amlogic/media/video_processor/videosync/Kconfig
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
636
drivers/amlogic/media/gdc/app/gdc_dmabuf.c
Normal file
636
drivers/amlogic/media/gdc/app/gdc_dmabuf.c
Normal file
@@ -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 <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mm_types.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <api/gdc_api.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
79
drivers/amlogic/media/gdc/app/gdc_dmabuf.h
Normal file
79
drivers/amlogic/media/gdc/app/gdc_dmabuf.h
Normal file
@@ -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 <linux/mm_types.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/dma-buf.h>
|
||||
|
||||
|
||||
#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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,13 +21,19 @@
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/dma-direction.h>
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -22,10 +22,17 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#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;
|
||||
|
||||
@@ -20,36 +20,27 @@
|
||||
|
||||
//changeable logs
|
||||
#include <linux/kernel.h>
|
||||
#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__
|
||||
|
||||
@@ -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;
|
||||
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_settings->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);
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user