ge2d: add ge2d dma_buf support [1/2]

PD#SWPL-4036

Problem:
don't support dma_buf

Solution:
add ge2d dma_buf support

Verify:
test pass on w400

Change-Id: I1277d04fb30753e579d5edc5f46f2406dc27217a
Signed-off-by: Pengcheng Chen <pengcheng.chen@amlogic.com>
Signed-off-by: Luan Yuan <luan.yuan@amlogic.com>
This commit is contained in:
Pengcheng Chen
2019-01-03 15:50:50 +08:00
committed by Luan Yuan
parent 5cc4b46815
commit b4f3eddec7
8 changed files with 1705 additions and 1 deletions

View File

@@ -14741,6 +14741,11 @@ F: drivers/amlogic/media/common/canvas/canvas_mgr.c
F: drivers/amlogic/media/common/vfm/vfm.c
F: include/linux/amlogic/media/camera/*
AMLOGIC multimedia
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 VIDEOSYNC
M: Jintao Xu <jintao.xu@amlogic.com>
F: drivers/amlogic/media/video_processor/videosync/Kconfig

View File

@@ -5,7 +5,8 @@ ge2d-objs = bitblt.o \
ge2d_wq.o \
stretchblt.o \
ge2d_main.o \
blend.o
blend.o \
ge2d_dmabuf.o
obj-$(CONFIG_AMLOGIC_MEDIA_GE2D) += ge2d.o
ccflags-y += -Iinclude/linux/media/ge2d/

View File

@@ -0,0 +1,634 @@
/*
* drivers/amlogic/media/common/ge2d/ge2d_dmabuf.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <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 "ge2d_log.h"
#include "ge2d_dmabuf.h"
/* dma free*/
static void aml_dma_put(void *buf_priv)
{
struct aml_dma_buf *buf = buf_priv;
if (!atomic_dec_and_test(&buf->refcount)) {
ge2d_log_dbg("aml_dma_put, refcont=%d\n",
atomic_read(&buf->refcount));
return;
}
if (buf->sgt_base) {
sg_free_table(buf->sgt_base);
kfree(buf->sgt_base);
}
dma_free_attrs(buf->dev, buf->size, buf->cookie, buf->dma_addr,
buf->attrs);
put_device(buf->dev);
kfree(buf);
ge2d_log_dbg("aml_dma_put free!\n");
}
static void *aml_dma_alloc(struct device *dev, unsigned long attrs,
unsigned long size, enum dma_data_direction dma_dir,
gfp_t gfp_flags)
{
struct aml_dma_buf *buf;
if (WARN_ON(!dev))
return (void *)(-EINVAL);
buf = kzalloc(sizeof(struct aml_dma_buf), GFP_KERNEL);
if (!buf)
return NULL;
if (attrs)
buf->attrs = attrs;
buf->cookie = dma_alloc_attrs(dev, size, &buf->dma_addr,
gfp_flags, buf->attrs);
if (!buf->cookie) {
dev_err(dev, "dma_alloc_coherent of size %ld failed\n", size);
kfree(buf);
return NULL;
}
if ((buf->attrs & DMA_ATTR_NO_KERNEL_MAPPING) == 0)
buf->vaddr = buf->cookie;
/* Prevent the device from being released while the buffer is used */
buf->dev = get_device(dev);
buf->size = size;
buf->dma_dir = dma_dir;
atomic_inc(&buf->refcount);
ge2d_log_dbg("aml_dma_alloc, refcont=%d\n",
atomic_read(&buf->refcount));
return buf;
}
static int aml_dma_mmap(void *buf_priv, struct vm_area_struct *vma)
{
struct aml_dma_buf *buf = buf_priv;
int ret;
if (!buf) {
pr_err("No buffer to map\n");
return -EINVAL;
}
/*
* dma_mmap_* uses vm_pgoff as in-buffer offset, but we want to
* map whole buffer
*/
vma->vm_pgoff = 0;
ret = dma_mmap_attrs(buf->dev, vma, buf->cookie,
buf->dma_addr, buf->size, buf->attrs);
if (ret) {
pr_err("Remapping memory failed, error: %d\n", ret);
return ret;
}
ge2d_log_dbg("mapped dma addr 0x%08lx at 0x%08lx, size %d\n",
(unsigned long)buf->dma_addr, vma->vm_start,
buf->size);
return 0;
}
/*********************************************/
/* DMABUF ops for exporters */
/*********************************************/
struct aml_attachment {
struct sg_table sgt;
enum dma_data_direction dma_dir;
};
static int aml_dmabuf_ops_attach(struct dma_buf *dbuf, struct device *dev,
struct dma_buf_attachment *dbuf_attach)
{
struct aml_attachment *attach;
unsigned int i;
struct scatterlist *rd, *wr;
struct sg_table *sgt;
struct aml_dma_buf *buf = dbuf->priv;
int ret;
attach = kzalloc(sizeof(*attach), GFP_KERNEL);
if (!attach)
return -ENOMEM;
sgt = &attach->sgt;
/* Copy the buf->base_sgt scatter list to the attachment, as we can't
* map the same scatter list to multiple attachments at the same time.
*/
ret = sg_alloc_table(sgt, buf->sgt_base->orig_nents, GFP_KERNEL);
if (ret) {
kfree(attach);
return -ENOMEM;
}
rd = buf->sgt_base->sgl;
wr = sgt->sgl;
for (i = 0; i < sgt->orig_nents; ++i) {
sg_set_page(wr, sg_page(rd), rd->length, rd->offset);
rd = sg_next(rd);
wr = sg_next(wr);
}
attach->dma_dir = DMA_NONE;
dbuf_attach->priv = attach;
return 0;
}
static void aml_dmabuf_ops_detach(struct dma_buf *dbuf,
struct dma_buf_attachment *db_attach)
{
struct aml_attachment *attach = db_attach->priv;
struct sg_table *sgt;
if (!attach)
return;
sgt = &attach->sgt;
/* release the scatterlist cache */
if (attach->dma_dir != DMA_NONE)
dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents,
attach->dma_dir);
sg_free_table(sgt);
kfree(attach);
db_attach->priv = NULL;
}
static struct sg_table *aml_dmabuf_ops_map(
struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir)
{
struct aml_attachment *attach = db_attach->priv;
/* stealing dmabuf mutex to serialize map/unmap operations */
struct mutex *lock = &db_attach->dmabuf->lock;
struct sg_table *sgt;
mutex_lock(lock);
sgt = &attach->sgt;
/* return previously mapped sg table */
if (attach->dma_dir == dma_dir) {
mutex_unlock(lock);
return sgt;
}
/* release any previous cache */
if (attach->dma_dir != DMA_NONE) {
dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents,
attach->dma_dir);
attach->dma_dir = DMA_NONE;
}
/* mapping to the client with new direction */
sgt->nents = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents,
dma_dir);
if (!sgt->nents) {
pr_err("failed to map scatterlist\n");
mutex_unlock(lock);
return (void *)(-EIO);
}
attach->dma_dir = dma_dir;
mutex_unlock(lock);
return sgt;
}
static void aml_dmabuf_ops_unmap(struct dma_buf_attachment *db_attach,
struct sg_table *sgt, enum dma_data_direction dma_dir)
{
/* nothing to be done here */
}
static void aml_dmabuf_ops_release(struct dma_buf *dbuf)
{
/* drop reference obtained in vb2_dc_get_dmabuf */
aml_dma_put(dbuf->priv);
}
static void *aml_dmabuf_ops_kmap(struct dma_buf *dbuf, unsigned long pgnum)
{
struct aml_dma_buf *buf = dbuf->priv;
return buf->vaddr ? buf->vaddr + pgnum * PAGE_SIZE : NULL;
}
static void *aml_dmabuf_ops_vmap(struct dma_buf *dbuf)
{
struct aml_dma_buf *buf = dbuf->priv;
return buf->vaddr;
}
static int aml_dmabuf_ops_mmap(struct dma_buf *dbuf,
struct vm_area_struct *vma)
{
return aml_dma_mmap(dbuf->priv, vma);
}
static struct dma_buf_ops ge2d_dmabuf_ops = {
.attach = aml_dmabuf_ops_attach,
.detach = aml_dmabuf_ops_detach,
.map_dma_buf = aml_dmabuf_ops_map,
.unmap_dma_buf = aml_dmabuf_ops_unmap,
.kmap = aml_dmabuf_ops_kmap,
.kmap_atomic = aml_dmabuf_ops_kmap,
.vmap = aml_dmabuf_ops_vmap,
.mmap = aml_dmabuf_ops_mmap,
.release = aml_dmabuf_ops_release,
};
static struct sg_table *get_base_sgt(struct aml_dma_buf *buf)
{
int ret;
struct sg_table *sgt;
sgt = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
if (!sgt)
return NULL;
ret = dma_get_sgtable(buf->dev, sgt, buf->cookie,
buf->dma_addr, buf->size);
if (ret < 0) {
dev_err(buf->dev, "failed to get scatterlist from DMA API\n");
kfree(sgt);
return NULL;
}
return sgt;
}
static struct dma_buf *get_dmabuf(void *buf_priv, unsigned long flags)
{
struct aml_dma_buf *buf = buf_priv;
struct dma_buf *dbuf;
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
exp_info.ops = &ge2d_dmabuf_ops;
exp_info.size = buf->size;
exp_info.flags = flags;
exp_info.priv = buf;
if (!buf->sgt_base)
buf->sgt_base = get_base_sgt(buf);
if (WARN_ON(!buf->sgt_base))
return NULL;
dbuf = dma_buf_export(&exp_info);
if (IS_ERR(dbuf))
return NULL;
/* dmabuf keeps reference to vb2 buffer */
atomic_inc(&buf->refcount);
ge2d_log_dbg("get_dmabuf, refcount=%d\n",
atomic_read(&buf->refcount));
return dbuf;
}
/* ge2d dma-buf api.h*/
static int find_empty_dma_buffer(struct aml_dma_buffer *buffer)
{
int i;
int found = 0;
for (i = 0; i < AML_MAX_DMABUF; i++) {
if (buffer->gd_buffer[i].alloc)
continue;
else {
ge2d_log_dbg("find_empty_dma_buffer i=%d\n", i);
found = 1;
break;
}
}
if (found)
return i;
else
return -1;
}
void *ge2d_dma_buffer_create(void)
{
int i;
struct aml_dma_buffer *buffer;
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
if (!buffer)
return NULL;
mutex_init(&buffer->lock);
for (i = 0; i < AML_MAX_DMABUF; i++) {
buffer->gd_buffer[i].mem_priv = NULL;
buffer->gd_buffer[i].index = 0;
buffer->gd_buffer[i].alloc = 0;
}
return buffer;
}
void ge2d_dma_buffer_destroy(struct aml_dma_buffer *buffer)
{
kfree(buffer);
}
int ge2d_dma_buffer_alloc(struct aml_dma_buffer *buffer,
struct device *dev,
struct ge2d_dmabuf_req_s *ge2d_req_buf)
{
void *buf;
unsigned int size;
int index;
if (WARN_ON(!dev))
return (-EINVAL);
if (!ge2d_req_buf)
return (-EINVAL);
if (!buffer)
return (-EINVAL);
size = PAGE_ALIGN(ge2d_req_buf->len);
if (size == 0)
return (-EINVAL);
index = find_empty_dma_buffer(buffer);
if ((index < 0) || (index >= AML_MAX_DMABUF)) {
pr_err("no empty buffer found\n");
return (-ENOMEM);
}
buf = aml_dma_alloc(dev, 0, size, ge2d_req_buf->dma_dir,
GFP_HIGHUSER | __GFP_ZERO);
if (!buf)
return (-ENOMEM);
mutex_lock(&(buffer->lock));
buffer->gd_buffer[index].mem_priv = buf;
buffer->gd_buffer[index].index = index;
buffer->gd_buffer[index].alloc = 1;
mutex_unlock(&(buffer->lock));
ge2d_req_buf->index = index;
return 0;
}
int ge2d_dma_buffer_free(struct aml_dma_buffer *buffer, int index)
{
struct aml_dma_buf *buf;
if (!buffer)
return (-EINVAL);
if ((index < 0) || (index >= AML_MAX_DMABUF))
return (-EINVAL);
buf = buffer->gd_buffer[index].mem_priv;
if (!buf) {
pr_err("aml_dma_buf is null\n");
return (-EINVAL);
}
aml_dma_put(buf);
return 0;
}
int ge2d_dma_buffer_export(struct aml_dma_buffer *buffer,
struct ge2d_dmabuf_exp_s *ge2d_exp_buf)
{
struct aml_dma_buf *buf;
struct dma_buf *dbuf;
int ret, index;
unsigned int flags;
if (!ge2d_exp_buf)
return (-EINVAL);
if (!buffer)
return (-EINVAL);
index = ge2d_exp_buf->index;
if ((index < 0) || (index >= AML_MAX_DMABUF))
return (-EINVAL);
flags = ge2d_exp_buf->flags;
buf = buffer->gd_buffer[index].mem_priv;
if (!buf) {
pr_err("aml_dma_buf is null\n");
return (-EINVAL);
}
dbuf = get_dmabuf(buf, flags & O_ACCMODE);
if (IS_ERR_OR_NULL(dbuf)) {
pr_err("failed to export buffer %d\n", index);
return -EINVAL;
}
ret = dma_buf_fd(dbuf, flags & ~O_ACCMODE);
if (ret < 0) {
pr_err("buffer %d, failed to export (%d)\n",
index, ret);
dma_buf_put(dbuf);
return ret;
}
ge2d_log_dbg("buffer %d,exported as %d descriptor\n",
index, ret);
ge2d_exp_buf->fd = ret;
return 0;
}
int ge2d_dma_buffer_map(struct aml_dma_cfg *cfg)
{
long ret = -1;
int fd = -1;
struct dma_buf *dbuf = NULL;
struct dma_buf_attachment *d_att = NULL;
struct sg_table *sg = NULL;
void *vaddr = NULL;
struct device *dev = NULL;
enum dma_data_direction dir;
if (cfg == NULL || (cfg->fd < 0) || cfg->dev == NULL) {
pr_err("error input param");
return -EINVAL;
}
fd = cfg->fd;
dev = cfg->dev;
dir = cfg->dir;
dbuf = dma_buf_get(fd);
if (dbuf == NULL) {
pr_err("failed to get dma buffer");
return -EINVAL;
}
d_att = dma_buf_attach(dbuf, dev);
if (d_att == NULL) {
pr_err("failed to set dma attach");
goto attach_err;
}
sg = dma_buf_map_attachment(d_att, dir);
if (sg == NULL) {
pr_err("failed to get dma sg");
goto map_attach_err;
}
ret = dma_buf_begin_cpu_access(dbuf, dir);
if (ret != 0) {
pr_err("failed to access dma buff");
goto access_err;
}
vaddr = dma_buf_vmap(dbuf);
if (vaddr == NULL) {
pr_err("failed to vmap dma buf");
goto vmap_err;
}
cfg->dbuf = dbuf;
cfg->attach = d_att;
cfg->vaddr = vaddr;
cfg->sg = sg;
return ret;
vmap_err:
dma_buf_end_cpu_access(dbuf, dir);
access_err:
dma_buf_unmap_attachment(d_att, sg, dir);
map_attach_err:
dma_buf_detach(dbuf, d_att);
attach_err:
dma_buf_put(dbuf);
return ret;
}
int ge2d_dma_buffer_get_phys(struct aml_dma_cfg *cfg, unsigned long *addr)
{
struct sg_table *sg_table;
struct page *page;
int ret;
ret = ge2d_dma_buffer_map(cfg);
if (ret < 0) {
pr_err("gdc_dma_buffer_map failed\n");
return ret;
}
if (cfg->sg) {
sg_table = cfg->sg;
page = sg_page(sg_table->sgl);
*addr = PFN_PHYS(page_to_pfn(page));
ret = 0;
}
ge2d_dma_buffer_unmap(cfg);
return ret;
}
void ge2d_dma_buffer_unmap(struct aml_dma_cfg *cfg)
{
int fd = -1;
struct dma_buf *dbuf = NULL;
struct dma_buf_attachment *d_att = NULL;
struct sg_table *sg = NULL;
void *vaddr = NULL;
struct device *dev = NULL;
enum dma_data_direction dir;
if (cfg == NULL || (cfg->fd < 0) || cfg->dev == NULL
|| cfg->dbuf == NULL || cfg->vaddr == NULL
|| cfg->attach == NULL || cfg->sg == NULL) {
pr_err("Error input param");
return;
}
fd = cfg->fd;
dev = cfg->dev;
dir = cfg->dir;
dbuf = cfg->dbuf;
vaddr = cfg->vaddr;
d_att = cfg->attach;
sg = cfg->sg;
dma_buf_vunmap(dbuf, vaddr);
dma_buf_end_cpu_access(dbuf, dir);
dma_buf_unmap_attachment(d_att, sg, dir);
dma_buf_detach(dbuf, d_att);
dma_buf_put(dbuf);
}
void ge2d_dma_buffer_dma_flush(struct device *dev, int fd)
{
struct dma_buf *dmabuf;
struct aml_dma_buf *buf;
ge2d_log_dbg("ge2d_dma_buffer_dma_flush fd=%d\n", fd);
dmabuf = dma_buf_get(fd);
if (IS_ERR(dmabuf)) {
pr_err("dma_buf_get failed\n");
return;
}
buf = dmabuf->priv;
if (!buf) {
pr_err("error input param");
return;
}
if (buf->size > 0)
dma_sync_single_for_device(buf->dev, buf->dma_addr,
buf->size, DMA_TO_DEVICE);
dma_buf_put(dmabuf);
}
void ge2d_dma_buffer_cache_flush(struct device *dev, int fd)
{
struct dma_buf *dmabuf;
struct aml_dma_buf *buf;
ge2d_log_dbg("ge2d_dma_buffer_cache_flush fd=%d\n", fd);
dmabuf = dma_buf_get(fd);
if (IS_ERR(dmabuf)) {
pr_err("dma_buf_get failed\n");
return;
}
buf = dmabuf->priv;
if (!buf) {
pr_err("error input param");
return;
}
if (buf->size > 0)
dma_sync_single_for_device(buf->dev, buf->dma_addr,
buf->size, DMA_FROM_DEVICE);
dma_buf_put(dmabuf);
}

View File

@@ -0,0 +1,81 @@
/*
* drivers/amlogic/media/common/ge2d/ge2d_dmabuf.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef _GE2D_DMABUF_H_
#define _GE2D_DMABUF_H_
#include <linux/mm_types.h>
#include <linux/mutex.h>
#include <linux/dma-buf.h>
/* Amlogic Headers */
#include <linux/amlogic/media/ge2d/ge2d.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 *ge2d_dma_buffer_create(void);
void ge2d_dma_buffer_destroy(struct aml_dma_buffer *buffer);
int ge2d_dma_buffer_alloc(struct aml_dma_buffer *buffer,
struct device *dev,
struct ge2d_dmabuf_req_s *ge2d_req_buf);
int ge2d_dma_buffer_free(struct aml_dma_buffer *buffer, int index);
int ge2d_dma_buffer_export(struct aml_dma_buffer *buffer,
struct ge2d_dmabuf_exp_s *ge2d_exp_buf);
int ge2d_dma_buffer_map(struct aml_dma_cfg *cfg);
void ge2d_dma_buffer_unmap(struct aml_dma_cfg *cfg);
int ge2d_dma_buffer_get_phys(struct aml_dma_cfg *cfg, unsigned long *addr);
void ge2d_dma_buffer_dma_flush(struct device *dev, int fd);
void ge2d_dma_buffer_cache_flush(struct device *dev, int fd);
#endif

View File

@@ -30,6 +30,7 @@
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_address.h>
#include <linux/of_reserved_mem.h>
#include <linux/reset.h>
#include <linux/clk.h>
#ifdef CONFIG_COMPAT
@@ -47,6 +48,7 @@
#include "ge2dgen.h"
#include "ge2d_log.h"
#include "ge2d_wq.h"
#include "ge2d_dmabuf.h"
#define GE2D_CLASS_NAME "ge2d"
#define MAX_GE2D_CLK 500000000
@@ -210,6 +212,197 @@ static int ge2d_open(struct inode *inode, struct file *file)
return 0;
}
static int ge2d_ioctl_config_ex_mem(struct ge2d_context_s *context,
unsigned int cmd, unsigned long args)
{
struct config_para_ex_memtype_s *ge2d_config_ex_mem;
struct config_ge2d_para_ex_s ge2d_para_config;
int ret = 0;
#ifdef CONFIG_COMPAT
struct compat_config_para_ex_memtype_s __user *uf_ex_mem;
struct compat_config_ge2d_para_ex_s __user *uf_ge2d_para;
int r = 0;
int i, j;
#endif
void __user *argp = (void __user *)args;
memset(&ge2d_para_config, 0, sizeof(struct config_ge2d_para_ex_s));
switch (cmd) {
case GE2D_CONFIG_EX_MEM:
ret = copy_from_user(&ge2d_para_config, argp,
sizeof(struct config_ge2d_para_ex_s));
ge2d_config_ex_mem = &(ge2d_para_config.para_config_memtype);
ret = ge2d_context_config_ex_mem(context, ge2d_config_ex_mem);
break;
#ifdef CONFIG_COMPAT
case GE2D_CONFIG_EX32_MEM:
uf_ge2d_para = (struct compat_config_ge2d_para_ex_s *)argp;
r |= get_user(ge2d_para_config.para_config_memtype.ge2d_magic,
&uf_ge2d_para->para_config_memtype.ge2d_magic);
ge2d_config_ex_mem = &(ge2d_para_config.para_config_memtype);
if (ge2d_para_config.para_config_memtype.ge2d_magic
== sizeof(struct config_para_ex_memtype_s)) {
struct config_para_ex_ion_s *pge2d_config_ex;
uf_ex_mem =
(struct compat_config_para_ex_memtype_s *)argp;
pge2d_config_ex =
&(ge2d_config_ex_mem->_ge2d_config_ex);
r = copy_from_user(
&pge2d_config_ex->src_para,
&uf_ex_mem->_ge2d_config_ex.src_para,
sizeof(struct src_dst_para_ex_s));
r |= copy_from_user(
&pge2d_config_ex->src2_para,
&uf_ex_mem->_ge2d_config_ex.src2_para,
sizeof(struct src_dst_para_ex_s));
r |= copy_from_user(
&pge2d_config_ex->dst_para,
&uf_ex_mem->_ge2d_config_ex.dst_para,
sizeof(struct src_dst_para_ex_s));
r |= copy_from_user(&pge2d_config_ex->src_key,
&uf_ex_mem->_ge2d_config_ex.src_key,
sizeof(struct src_key_ctrl_s));
r |= copy_from_user(&pge2d_config_ex->src2_key,
&uf_ex_mem->_ge2d_config_ex.src2_key,
sizeof(struct src_key_ctrl_s));
r |= get_user(pge2d_config_ex->src1_cmult_asel,
&uf_ex_mem->_ge2d_config_ex.src1_cmult_asel);
r |= get_user(pge2d_config_ex->src2_cmult_asel,
&uf_ex_mem->_ge2d_config_ex.src2_cmult_asel);
r |= get_user(pge2d_config_ex->alu_const_color,
&uf_ex_mem->_ge2d_config_ex.alu_const_color);
r |= get_user(pge2d_config_ex->src1_gb_alpha_en,
&uf_ex_mem->_ge2d_config_ex.src1_gb_alpha_en);
r |= get_user(pge2d_config_ex->src1_gb_alpha,
&uf_ex_mem->_ge2d_config_ex.src1_gb_alpha);
#ifdef CONFIG_GE2D_SRC2
r |= get_user(pge2d_config_ex->src2_gb_alpha_en,
&uf_ex_mem->_ge2d_config_ex.src2_gb_alpha_en);
r |= get_user(pge2d_config_ex->src2_gb_alpha,
&uf_ex_mem->_ge2d_config_ex.src2_gb_alpha);
#endif
r |= get_user(pge2d_config_ex->op_mode,
&uf_ex_mem->_ge2d_config_ex.op_mode);
r |= get_user(pge2d_config_ex->bitmask_en,
&uf_ex_mem->_ge2d_config_ex.bitmask_en);
r |= get_user(pge2d_config_ex->bytemask_only,
&uf_ex_mem->_ge2d_config_ex.bytemask_only);
r |= get_user(pge2d_config_ex->bitmask,
&uf_ex_mem->_ge2d_config_ex.bitmask);
r |= get_user(pge2d_config_ex->dst_xy_swap,
&uf_ex_mem->_ge2d_config_ex.dst_xy_swap);
r |= get_user(pge2d_config_ex->hf_init_phase,
&uf_ex_mem->_ge2d_config_ex.hf_init_phase);
r |= get_user(pge2d_config_ex->hf_rpt_num,
&uf_ex_mem->_ge2d_config_ex.hf_rpt_num);
r |= get_user(pge2d_config_ex->hsc_start_phase_step,
&uf_ex_mem->_ge2d_config_ex
.hsc_start_phase_step);
r |= get_user(pge2d_config_ex->hsc_phase_slope,
&uf_ex_mem->_ge2d_config_ex.hsc_phase_slope);
r |= get_user(pge2d_config_ex->vf_init_phase,
&uf_ex_mem->_ge2d_config_ex.vf_init_phase);
r |= get_user(pge2d_config_ex->vf_rpt_num,
&uf_ex_mem->_ge2d_config_ex.vf_rpt_num);
r |= get_user(pge2d_config_ex->vsc_start_phase_step,
&uf_ex_mem->_ge2d_config_ex
.vsc_start_phase_step);
r |= get_user(pge2d_config_ex->vsc_phase_slope,
&uf_ex_mem->_ge2d_config_ex.vsc_phase_slope);
r |= get_user(
pge2d_config_ex->src1_vsc_phase0_always_en,
&uf_ex_mem->_ge2d_config_ex
.src1_vsc_phase0_always_en);
r |= get_user(
pge2d_config_ex->src1_hsc_phase0_always_en,
&uf_ex_mem->_ge2d_config_ex
.src1_hsc_phase0_always_en);
r |= get_user(
pge2d_config_ex->src1_hsc_rpt_ctrl,
&uf_ex_mem->_ge2d_config_ex.src1_hsc_rpt_ctrl);
r |= get_user(
pge2d_config_ex->src1_vsc_rpt_ctrl,
&uf_ex_mem->_ge2d_config_ex.src1_vsc_rpt_ctrl);
for (i = 0; i < 4; i++) {
struct config_planes_ion_s *psrc_planes;
psrc_planes =
&pge2d_config_ex->src_planes[i];
r |= get_user(psrc_planes->addr,
&uf_ex_mem->_ge2d_config_ex
.src_planes[i].addr);
r |= get_user(psrc_planes->w,
&uf_ex_mem->_ge2d_config_ex
.src_planes[i].w);
r |= get_user(psrc_planes->h,
&uf_ex_mem->_ge2d_config_ex
.src_planes[i].h);
r |= get_user(psrc_planes->shared_fd,
&uf_ex_mem->_ge2d_config_ex
.src_planes[i].shared_fd);
}
for (i = 0; i < 4; i++) {
struct config_planes_ion_s *psrc2_planes;
psrc2_planes =
&pge2d_config_ex->src2_planes[i];
r |= get_user(psrc2_planes->addr,
&uf_ex_mem->_ge2d_config_ex
.src2_planes[i].addr);
r |= get_user(psrc2_planes->w,
&uf_ex_mem->_ge2d_config_ex
.src2_planes[i].w);
r |= get_user(psrc2_planes->h,
&uf_ex_mem->_ge2d_config_ex
.src2_planes[i].h);
r |= get_user(psrc2_planes->shared_fd,
&uf_ex_mem->_ge2d_config_ex
.src2_planes[i].shared_fd);
}
for (j = 0; j < 4; j++) {
struct config_planes_ion_s *pdst_planes;
pdst_planes =
&pge2d_config_ex->dst_planes[j];
r |= get_user(pdst_planes->addr,
&uf_ex_mem->_ge2d_config_ex
.dst_planes[j].addr);
r |= get_user(pdst_planes->w,
&uf_ex_mem->_ge2d_config_ex
.dst_planes[j].w);
r |= get_user(pdst_planes->h,
&uf_ex_mem->_ge2d_config_ex
.dst_planes[j].h);
r |= get_user(pdst_planes->shared_fd,
&uf_ex_mem->_ge2d_config_ex
.dst_planes[j].shared_fd);
}
r |= get_user(ge2d_config_ex_mem->src1_mem_alloc_type,
&uf_ex_mem->src1_mem_alloc_type);
r |= get_user(ge2d_config_ex_mem->src2_mem_alloc_type,
&uf_ex_mem->src2_mem_alloc_type);
r |= get_user(ge2d_config_ex_mem->dst_mem_alloc_type,
&uf_ex_mem->dst_mem_alloc_type);
}
if (r) {
pr_err("GE2D_CONFIG_EX32 get parameter failed .\n");
return -EFAULT;
}
ret = ge2d_context_config_ex_mem(context, ge2d_config_ex_mem);
break;
#endif
}
return ret;
}
static long ge2d_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
{
struct ge2d_context_s *context = NULL;
@@ -217,6 +410,8 @@ static long ge2d_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
struct ge2d_para_s para;
struct config_para_ex_s ge2d_config_ex;
struct config_para_ex_ion_s ge2d_config_ex_ion;
struct ge2d_dmabuf_req_s ge2d_req_buf;
struct ge2d_dmabuf_exp_s ge2d_exp_buf;
int ret = 0;
#ifdef CONFIG_COMPAT
struct compat_config_para_s __user *uf;
@@ -226,12 +421,15 @@ static long ge2d_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
int i, j;
#endif
int cap_mask = 0;
int index = 0, dma_fd;
void __user *argp = (void __user *)args;
context = (struct ge2d_context_s *)filp->private_data;
memset(&ge2d_config, 0, sizeof(struct config_para_s));
memset(&ge2d_config_ex, 0, sizeof(struct config_para_ex_s));
memset(&ge2d_config_ex_ion, 0, sizeof(struct config_para_ex_ion_s));
memset(&ge2d_req_buf, 0, sizeof(struct ge2d_dmabuf_req_s));
memset(&ge2d_exp_buf, 0, sizeof(struct ge2d_dmabuf_exp_s));
#ifdef CONFIG_AMLOGIC_MEDIA_GE2D_MORE_SECURITY
switch (cmd) {
case GE2D_CONFIG:
@@ -538,6 +736,39 @@ static long ge2d_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
case GE2D_SET_COEF:
case GE2D_ANTIFLICKER_ENABLE:
break;
case GE2D_REQUEST_BUFF:
ret = copy_from_user(&ge2d_req_buf, argp,
sizeof(struct ge2d_dmabuf_req_s));
if (ret < 0) {
pr_err("Error user param\n");
return -EINVAL;
}
break;
case GE2D_EXP_BUFF:
ret = copy_from_user(&ge2d_exp_buf, argp,
sizeof(struct ge2d_dmabuf_exp_s));
if (ret < 0) {
pr_err("Error user param\n");
return -EINVAL;
}
break;
case GE2D_FREE_BUFF:
ret = copy_from_user(&index, argp,
sizeof(int));
if (ret < 0) {
pr_err("Error user param\n");
return -EINVAL;
}
break;
case GE2D_SYNC_DEVICE:
case GE2D_SYNC_CPU:
ret = copy_from_user(&dma_fd, argp,
sizeof(int));
if (ret < 0) {
pr_err("Error user param\n");
return -EINVAL;
}
break;
case GE2D_CONFIG_OLD:
case GE2D_CONFIG_EX_OLD:
case GE2D_SRCCOLORKEY_OLD:
@@ -568,6 +799,12 @@ static long ge2d_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
#endif
ret = ge2d_context_config_ex_ion(context, &ge2d_config_ex_ion);
break;
case GE2D_CONFIG_EX_MEM:
#ifdef CONFIG_COMPAT
case GE2D_CONFIG_EX32_MEM:
#endif
ret = ge2d_ioctl_config_ex_mem(context, cmd, args);
break;
case GE2D_SET_COEF:
ge2d_wq_set_scale_coef(context, args & 0xff, args >> 16);
break;
@@ -744,6 +981,27 @@ static long ge2d_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
para.dst_rect.x, para.dst_rect.y,
para.dst_rect.w, para.dst_rect.h);
break;
case GE2D_REQUEST_BUFF:
ret = ge2d_buffer_alloc(&ge2d_req_buf);
if (ret == 0)
ret = copy_to_user(argp, &ge2d_req_buf,
sizeof(struct ge2d_dmabuf_req_s));
break;
case GE2D_EXP_BUFF:
ret = ge2d_buffer_export(&ge2d_exp_buf);
if (ret == 0)
ret = copy_to_user(argp, &ge2d_exp_buf,
sizeof(struct ge2d_dmabuf_exp_s));
break;
case GE2D_FREE_BUFF:
ret = ge2d_buffer_free(index);
break;
case GE2D_SYNC_DEVICE:
ge2d_buffer_dma_flush(dma_fd);
break;
case GE2D_SYNC_CPU:
ge2d_buffer_cache_flush(dma_fd);
break;
}
return ret;
}
@@ -961,6 +1219,9 @@ static int ge2d_probe(struct platform_device *pdev)
(void *)res.start, (int)resource_size(&res));
}
}
ret = of_reserved_mem_device_init(&(pdev->dev));
if (ret < 0)
ge2d_log_info("reserved mem init failed\n");
ret = ge2d_wq_init(pdev, irq, clk_gate);

View File

@@ -41,6 +41,7 @@
#include "ge2d_io.h"
#include "ge2d_reg.h"
#include "ge2d_wq.h"
#include "ge2d_dmabuf.h"
#include "osd_io.h"
#include "osd_hw.h"
@@ -928,6 +929,49 @@ static int build_ge2d_addr_config_ion(
return ret;
}
static int build_ge2d_addr_config_dma(
struct config_planes_ion_s *plane,
unsigned int format,
unsigned int *addr,
unsigned int *stride,
unsigned int dir
)
{
int ret = -1;
int bpp_value = bpp(format);
unsigned long addr_temp = 0;
bpp_value /= 8;
ge2d_log_dbg("build_ge2d_addr_config_ion bpp_value=%d\n",
bpp_value);
if (plane) {
if (plane[0].shared_fd) {
struct aml_dma_cfg cfg;
cfg.fd = plane[0].shared_fd;
cfg.dev = &(ge2d_manager.pdev->dev);
cfg.dir = dir;
ret = ge2d_dma_buffer_get_phys(&cfg, &addr_temp);
if (ret != 0)
return ret;
}
plane[0].addr += addr_temp;
if (plane[0].addr) {
*addr = plane[0].addr;
*stride = plane[0].w * bpp_value;
ret = 0;
}
/* not support multi-src_planes */
if ((plane[1].addr) ||
(plane[2].addr) ||
(plane[3].addr)) {
ge2d_log_info("ge2d not support NV21 mode\n");
ret = -1;
}
}
return ret;
}
static int build_ge2d_config_ex(struct config_planes_s *plane,
unsigned int format,
unsigned int *canvas_index,
@@ -1066,6 +1110,84 @@ static int build_ge2d_config_ex_ion(struct config_planes_ion_s *plane,
}
return ret;
}
static int build_ge2d_config_ex_dma(struct config_planes_ion_s *plane,
unsigned int format,
unsigned int *canvas_index,
int index,
unsigned int *r_offset,
unsigned int dir)
{
int bpp_value = bpp(format);
int ret = -1;
unsigned long addr;
bpp_value /= 8;
index &= 0xff;
if (plane) {
if (plane[0].shared_fd) {
struct aml_dma_cfg cfg;
cfg.fd = plane[0].shared_fd;
cfg.dev = &(ge2d_manager.pdev->dev);
cfg.dir = dir;
ret = ge2d_dma_buffer_get_phys(&cfg, &addr);
ge2d_log_info("phys: addr=%lx\n", addr);
if (ret != 0)
return ret;
plane[0].addr += addr;
*canvas_index = index;
*r_offset += 1;
#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
canvas_config(index++, plane[0].addr,
plane[0].w * bpp_value,
plane[0].h,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
#endif
ret = 0;
}
/* multi-src_planes */
if (plane[1].addr) {
plane[1].addr += plane[0].addr;
*canvas_index |= index << 8;
*r_offset += 1;
#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
canvas_config(index++, plane[1].addr,
plane[1].w * bpp_value,
plane[1].h,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
#endif
}
if (plane[2].addr) {
plane[2].addr += plane[0].addr;
*canvas_index |= index << 16;
*r_offset += 1;
#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
canvas_config(index++, plane[2].addr,
plane[2].w * bpp_value,
plane[2].h,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
#endif
}
if (plane[3].addr) {
plane[3].addr += plane[0].addr;
*canvas_index |= index << 24;
*r_offset += 1;
#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
canvas_config(index++, plane[3].addr,
plane[3].w * bpp_value,
plane[3].h,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
#endif
}
}
return ret;
}
int ge2d_context_config_ex(struct ge2d_context_s *context,
struct config_para_ex_s *ge2d_config)
{
@@ -1814,6 +1936,516 @@ int ge2d_context_config_ex_ion(struct ge2d_context_s *context,
return 0;
}
int ge2d_context_config_ex_mem(struct ge2d_context_s *context,
struct config_para_ex_memtype_s *ge2d_config_mem)
{
struct src_dst_para_s tmp;
unsigned int index = 0;
unsigned int alloc_canvas_offset = 0;
struct ge2d_src1_gen_s *src1_gen_cfg;
struct ge2d_src2_dst_data_s *src2_dst_data_cfg;
struct ge2d_src2_dst_gen_s *src2_dst_gen_cfg;
struct ge2d_dp_gen_s *dp_gen_cfg;
struct ge2d_cmd_s *ge2d_cmd_cfg;
int top, left, width, height;
unsigned int src_addr = 0, src2_addr = 0, dst_addr = 0;
unsigned int src_stride = 0, src2_stride = 0, dst_stride = 0;
struct config_para_ex_ion_s *ge2d_config;
ge2d_config = &(ge2d_config_mem->_ge2d_config_ex);
/* setup src and dst */
switch (ge2d_config->src_para.mem_type) {
case CANVAS_OSD0:
case CANVAS_OSD1:
if (setup_display_property(&tmp,
(ge2d_config->src_para.mem_type == CANVAS_OSD0) ?
OSD1_CANVAS_INDEX : OSD2_CANVAS_INDEX) < 0)
return -1;
ge2d_config->src_para.canvas_index = tmp.canvas_index;
ge2d_config->src_para.format = tmp.ge2d_color_index;
src_addr = tmp.phy_addr;
src_stride = tmp.stride;
ge2d_log_dbg("ge2d: src1-->type: osd%d, format: 0x%x !!\n",
ge2d_config->src_para.mem_type - CANVAS_OSD0,
ge2d_config->src_para.format);
top = ge2d_config->src_para.top;
left = ge2d_config->src_para.left;
width = ge2d_config->src_para.width;
height = ge2d_config->src_para.height;
if ((left + width > tmp.xres) ||
(top + height > tmp.yres)) {
ge2d_log_dbg("ge2d src error: out of range\n");
return -1;
}
ge2d_config->src_para.width = tmp.xres;
ge2d_config->src_para.height = tmp.yres;
ge2d_log_dbg("ge2d osd phy_addr:0x%x,stride=0x%x,format:0x%x\n",
src_addr,
src_stride,
ge2d_config->src_para.format);
break;
case CANVAS_ALLOC:
top = ge2d_config->src_para.top;
left = ge2d_config->src_para.left;
width = ge2d_config->src_para.width;
height = ge2d_config->src_para.height;
if ((left + width > ge2d_config->src_planes[0].w)
|| (top + height > ge2d_config->src_planes[0].h)) {
ge2d_log_dbg("ge2d error: src alloc, out of range\n");
return -1;
}
if (ge2d_meson_dev.canvas_status == 1) {
if (ge2d_config_mem->src1_mem_alloc_type ==
AML_GE2D_MEM_ION) {
if (build_ge2d_addr_config_ion(
&ge2d_config->src_planes[0],
ge2d_config->src_para.format,
&src_addr,
&src_stride) < 0)
return -1;
ge2d_log_dbg("ge2d ion alloc phy_addr:0x%x,stride=0x%x,format:0x%x\n",
src_addr,
src_stride,
ge2d_config->src_para.format);
} else if (ge2d_config_mem->src1_mem_alloc_type ==
AML_GE2D_MEM_DMABUF) {
if (build_ge2d_addr_config_dma(
&ge2d_config->src_planes[0],
ge2d_config->src_para.format,
&src_addr,
&src_stride,
DMA_TO_DEVICE) < 0)
return -1;
ge2d_log_dbg("ge2d dma alloc phy_addr:0x%x,stride=0x%x,format:0x%x\n",
src_addr,
src_stride,
ge2d_config->src_para.format);
}
} else {
if (ge2d_config_mem->src1_mem_alloc_type ==
AML_GE2D_MEM_ION) {
if (build_ge2d_config_ex_ion(
&ge2d_config->src_planes[0],
ge2d_config->src_para.format,
&index,
ALLOC_CANVAS_INDEX +
alloc_canvas_offset,
&alloc_canvas_offset) < 0)
return -1;
ge2d_config->src_para.canvas_index = index;
ge2d_log_dbg("ge2d ion alloc canvas index:0x%x, format:0x%x\n",
index, ge2d_config->src_para.format);
} else if (ge2d_config_mem->src1_mem_alloc_type ==
AML_GE2D_MEM_DMABUF) {
if (build_ge2d_config_ex_dma(
&ge2d_config->src_planes[0],
ge2d_config->src_para.format,
&index,
ALLOC_CANVAS_INDEX +
alloc_canvas_offset,
&alloc_canvas_offset,
DMA_TO_DEVICE) < 0)
return -1;
ge2d_config->src_para.canvas_index = index;
ge2d_log_dbg("ge2d dma alloc canvas index:0x%x, format:0x%x\n",
index, ge2d_config->src_para.format);
}
}
break;
default:
break;
}
switch (ge2d_config->src2_para.mem_type) {
case CANVAS_OSD0:
case CANVAS_OSD1:
if (setup_display_property(&tmp,
(ge2d_config->src2_para.mem_type == CANVAS_OSD0) ?
OSD1_CANVAS_INDEX : OSD2_CANVAS_INDEX) < 0)
return -1;
ge2d_config->src2_para.canvas_index = tmp.canvas_index;
ge2d_config->src2_para.format = tmp.ge2d_color_index;
src2_addr = tmp.phy_addr;
src2_stride = tmp.stride;
ge2d_log_dbg("ge2d: src2-->type: osd%d, format: 0x%x !!\n",
ge2d_config->src2_para.mem_type - CANVAS_OSD0,
ge2d_config->src2_para.format);
top = ge2d_config->src2_para.top;
left = ge2d_config->src2_para.left;
width = ge2d_config->src2_para.width;
height = ge2d_config->src2_para.height;
if ((left + width > tmp.xres) || (top + height > tmp.yres)) {
ge2d_log_dbg("ge2d error: src2: osd%d, out of range\n",
ge2d_config->src2_para.mem_type - CANVAS_OSD0);
return -1;
}
ge2d_config->src2_para.width = tmp.xres;
ge2d_config->src2_para.height = tmp.yres;
ge2d_log_dbg("ge2d osd phy_addr:0x%x,stride=0x%x,format:0x%x\n",
src2_addr,
src2_stride,
ge2d_config->src2_para.format);
break;
case CANVAS_ALLOC:
top = ge2d_config->src2_para.top;
left = ge2d_config->src2_para.left;
width = ge2d_config->src2_para.width;
height = ge2d_config->src2_para.height;
if ((left + width > ge2d_config->src2_planes[0].w)
|| (top + height > ge2d_config->src2_planes[0].h)) {
ge2d_log_dbg("ge2d error: src2: alloc, out of range\n");
return -1;
}
/*if (ge2d_config->src2_planes[0].addr ==
* ge2d_config->src_planes[0].addr)
* index = ge2d_config->src_para.canvas_index;
* else
*/
if (ge2d_meson_dev.canvas_status == 1) {
if (ge2d_config_mem->src2_mem_alloc_type ==
AML_GE2D_MEM_ION) {
if (build_ge2d_addr_config_ion(
&ge2d_config->src2_planes[0],
ge2d_config->src2_para.format,
&src2_addr,
&src2_stride) < 0)
return -1;
ge2d_log_dbg("ge2d ion alloc phy_addr:0x%x,stride=0x%x,format:0x%x\n",
src2_addr,
src2_stride,
ge2d_config->src2_para.format);
} else if (ge2d_config_mem->src2_mem_alloc_type ==
AML_GE2D_MEM_DMABUF) {
if (build_ge2d_addr_config_dma(
&ge2d_config->src2_planes[0],
ge2d_config->src2_para.format,
&src2_addr,
&src2_stride,
DMA_TO_DEVICE) < 0)
return -1;
ge2d_log_dbg("ge2d dma alloc phy_addr:0x%x,stride=0x%x,format:0x%x\n",
src2_addr,
src2_stride,
ge2d_config->src2_para.format);
}
} else {
if (ge2d_config_mem->src2_mem_alloc_type ==
AML_GE2D_MEM_ION) {
if (build_ge2d_config_ex_ion(
&ge2d_config->src2_planes[0],
ge2d_config->src2_para.format,
&index,
ALLOC_CANVAS_INDEX +
alloc_canvas_offset,
&alloc_canvas_offset) < 0)
return -1;
ge2d_config->src2_para.canvas_index = index;
ge2d_log_dbg("ge2d src2 ion alloc, canvas index:0x%x,format:0x%x\n",
index, ge2d_config->src2_para.format);
} else if (ge2d_config_mem->src2_mem_alloc_type ==
AML_GE2D_MEM_DMABUF) {
if (build_ge2d_config_ex_dma(
&ge2d_config->src2_planes[0],
ge2d_config->src2_para.format,
&index,
ALLOC_CANVAS_INDEX +
alloc_canvas_offset,
&alloc_canvas_offset,
DMA_TO_DEVICE) < 0)
return -1;
ge2d_config->src2_para.canvas_index = index;
ge2d_log_dbg("ge2d src2 dma alloc, canvas index:0x%x,format:0x%x\n",
index, ge2d_config->src2_para.format);
}
}
break;
default:
break;
}
switch (ge2d_config->dst_para.mem_type) {
case CANVAS_OSD0:
case CANVAS_OSD1:
if (setup_display_property(&tmp,
(ge2d_config->dst_para.mem_type == CANVAS_OSD0) ?
OSD1_CANVAS_INDEX : OSD2_CANVAS_INDEX) < 0)
return -1;
ge2d_config->dst_para.canvas_index = tmp.canvas_index;
ge2d_config->dst_para.format = tmp.ge2d_color_index;
dst_addr = tmp.phy_addr;
dst_stride = tmp.stride;
ge2d_log_dbg("ge2d: dst-->type: osd%d, format: 0x%x !!\n",
ge2d_config->dst_para.mem_type - CANVAS_OSD0,
ge2d_config->dst_para.format);
top = ge2d_config->dst_para.top;
left = ge2d_config->dst_para.left;
width = ge2d_config->dst_para.width;
height = ge2d_config->dst_para.height;
if ((left + width > tmp.xres) || (top + height > tmp.yres)) {
ge2d_log_dbg("ge2d error: dst: osd%d, out of range\n",
ge2d_config->dst_para.mem_type - CANVAS_OSD0);
return -1;
}
ge2d_config->dst_para.width = tmp.xres;
ge2d_config->dst_para.height = tmp.yres;
ge2d_log_dbg("ge2d osd phy_addr:0x%x,stride=0x%x,format:0x%x\n",
dst_addr,
dst_stride,
ge2d_config->dst_para.format);
break;
case CANVAS_ALLOC:
top = ge2d_config->dst_para.top;
left = ge2d_config->dst_para.left;
width = ge2d_config->dst_para.width;
height = ge2d_config->dst_para.height;
if ((left + width > ge2d_config->dst_planes[0].w)
|| (top + height > ge2d_config->dst_planes[0].h)) {
ge2d_log_dbg("ge2d error: dst: alloc, out of range\n");
return -1;
}
/*if (ge2d_config->dst_planes[0].addr ==
* ge2d_config->src_planes[0].addr)
* index = ge2d_config->src_para.canvas_index;
* else if (ge2d_config->dst_planes[0].addr ==
* ge2d_config->src2_planes[0].addr)
* index = ge2d_config->src2_para.canvas_index;
* else
*/
if (ge2d_meson_dev.canvas_status == 1) {
if (ge2d_config_mem->dst_mem_alloc_type ==
AML_GE2D_MEM_ION) {
if (build_ge2d_addr_config_ion(
&ge2d_config->dst_planes[0],
ge2d_config->dst_para.format,
&dst_addr,
&dst_stride) < 0)
return -1;
ge2d_log_dbg("ge2d ion alloc phy_addr:0x%x,stride=0x%x,format:0x%x\n",
dst_addr,
dst_stride,
ge2d_config->dst_para.format);
} else if (ge2d_config_mem->dst_mem_alloc_type ==
AML_GE2D_MEM_DMABUF) {
if (build_ge2d_addr_config_dma(
&ge2d_config->dst_planes[0],
ge2d_config->dst_para.format,
&dst_addr,
&dst_stride,
DMA_FROM_DEVICE) < 0)
return -1;
ge2d_log_dbg("ge2d dma alloc phy_addr:0x%x,stride=0x%x,format:0x%x\n",
dst_addr,
dst_stride,
ge2d_config->dst_para.format);
}
} else {
if (ge2d_config_mem->dst_mem_alloc_type ==
AML_GE2D_MEM_ION) {
if (build_ge2d_config_ex_ion(
&ge2d_config->dst_planes[0],
ge2d_config->dst_para.format,
&index,
ALLOC_CANVAS_INDEX +
alloc_canvas_offset,
&alloc_canvas_offset) < 0)
return -1;
ge2d_config->dst_para.canvas_index = index;
ge2d_log_dbg("ge2d: dst ion alloc, index:0x%x, format:0x%x\n",
index, ge2d_config->dst_para.format);
} else if (ge2d_config_mem->dst_mem_alloc_type ==
AML_GE2D_MEM_DMABUF) {
if (build_ge2d_config_ex_dma(
&ge2d_config->dst_planes[0],
ge2d_config->dst_para.format,
&index,
ALLOC_CANVAS_INDEX +
alloc_canvas_offset,
&alloc_canvas_offset,
DMA_FROM_DEVICE) < 0)
return -1;
ge2d_config->dst_para.canvas_index = index;
ge2d_log_dbg("ge2d: dst dma alloc, index:0x%x, format:0x%x\n",
index, ge2d_config->dst_para.format);
}
}
break;
default:
break;
}
ge2dgen_rendering_dir(context, ge2d_config->src_para.x_rev,
ge2d_config->src_para.y_rev,
ge2d_config->dst_para.x_rev,
ge2d_config->dst_para.y_rev,
ge2d_config->dst_xy_swap);
ge2dgen_const_color(context, ge2d_config->alu_const_color);
ge2dgen_src(context, ge2d_config->src_para.canvas_index,
ge2d_config->src_para.format,
src_addr,
src_stride);
ge2dgen_src_clip(context, ge2d_config->src_para.left,
ge2d_config->src_para.top,
ge2d_config->src_para.width,
ge2d_config->src_para.height);
ge2dgen_src_key(context, ge2d_config->src_key.key_enable,
ge2d_config->src_key.key_color,
ge2d_config->src_key.key_mask,
ge2d_config->src_key.key_mode);
#ifdef CONFIG_GE2D_SRC2
ge2dgent_src_gbalpha(context, ge2d_config->src1_gb_alpha,
ge2d_config->src2_gb_alpha);
#else
ge2dgent_src_gbalpha(context, ge2d_config->src1_gb_alpha, 0);
#endif
ge2dgen_src_color(context, ge2d_config->src_para.color);
ge2dgen_src2(context, ge2d_config->src2_para.canvas_index,
ge2d_config->src2_para.format,
src2_addr,
src2_stride);
ge2dgen_src2_clip(context, ge2d_config->src2_para.left,
ge2d_config->src2_para.top,
ge2d_config->src2_para.width,
ge2d_config->src2_para.height);
ge2dgen_dst(context, ge2d_config->dst_para.canvas_index,
ge2d_config->dst_para.format,
dst_addr,
dst_stride);
ge2dgen_dst_clip(context, ge2d_config->dst_para.left,
ge2d_config->dst_para.top,
ge2d_config->dst_para.width,
ge2d_config->dst_para.height,
DST_CLIP_MODE_INSIDE);
src1_gen_cfg = ge2d_wq_get_src_gen(context);
src1_gen_cfg->fill_mode = ge2d_config->src_para.fill_mode;
src1_gen_cfg->chfmt_rpt_pix = 0;
src1_gen_cfg->cvfmt_rpt_pix = 0;
/* src1_gen_cfg->clipx_start_ex = 0; */
/* src1_gen_cfg->clipx_end_ex = 1; */
/* src1_gen_cfg->clipy_start_ex = 1; */
/* src1_gen_cfg->clipy_end_ex = 1; */
src2_dst_data_cfg = ge2d_wq_get_dst_data(context);
src2_dst_data_cfg->src2_def_color = ge2d_config->src2_para.color;
src2_dst_gen_cfg = ge2d_wq_get_dst_gen(context);
src2_dst_gen_cfg->src2_fill_mode = ge2d_config->src2_para.fill_mode;
dp_gen_cfg = ge2d_wq_get_dp_gen(context);
dp_gen_cfg->src1_vsc_phase0_always_en =
ge2d_config->src1_hsc_phase0_always_en;
dp_gen_cfg->src1_hsc_phase0_always_en =
ge2d_config->src1_vsc_phase0_always_en;
if ((context->config.v_scale_coef_type == FILTER_TYPE_GAU0) ||
(context->config.v_scale_coef_type == FILTER_TYPE_GAU0_BOT) ||
(context->config.v_scale_coef_type == FILTER_TYPE_GAU1) ||
(context->config.h_scale_coef_type == FILTER_TYPE_GAU0) ||
(context->config.h_scale_coef_type == FILTER_TYPE_GAU0_BOT) ||
(context->config.h_scale_coef_type == FILTER_TYPE_GAU1)) {
/* 1bit, 0: using minus, 1: using repeat data */
dp_gen_cfg->src1_hsc_rpt_ctrl = ge2d_config->src1_hsc_rpt_ctrl;
/* 1bit, 0: using minus 1: using repeat data */
dp_gen_cfg->src1_vsc_rpt_ctrl = ge2d_config->src1_vsc_rpt_ctrl;
} else {
/* 1bit, 0: using minus, 1: using repeat data */
dp_gen_cfg->src1_hsc_rpt_ctrl = 1;
/* 1bit, 0: using minus 1: using repeat data */
dp_gen_cfg->src1_vsc_rpt_ctrl = 1;
}
dp_gen_cfg->src1_gb_alpha = ge2d_config->src1_gb_alpha & 0xff;
dp_gen_cfg->src1_gb_alpha_en = ge2d_config->src1_gb_alpha_en & 1;
#ifdef CONFIG_GE2D_SRC2
dp_gen_cfg->src2_gb_alpha = ge2d_config->src2_gb_alpha & 0xff;
dp_gen_cfg->src2_gb_alpha_en = ge2d_config->src2_gb_alpha_en & 1;
#endif
dp_gen_cfg->src2_key_en = ge2d_config->src2_key.key_enable;
dp_gen_cfg->src2_key_mode = ge2d_config->src2_key.key_mode;
dp_gen_cfg->src2_key = ge2d_config->src2_key.key_color;
dp_gen_cfg->src2_key_mask = ge2d_config->src2_key.key_mask;
dp_gen_cfg->bitmask_en = ge2d_config->bitmask_en;
dp_gen_cfg->bitmask = ge2d_config->bitmask;
dp_gen_cfg->bytemask_only = ge2d_config->bytemask_only;
ge2d_cmd_cfg = ge2d_wq_get_cmd(context);
ge2d_cmd_cfg->src1_fill_color_en = ge2d_config->src_para.fill_color_en;
ge2d_cmd_cfg->src2_x_rev = ge2d_config->src2_para.x_rev;
ge2d_cmd_cfg->src2_y_rev = ge2d_config->src2_para.y_rev;
ge2d_cmd_cfg->src2_fill_color_en =
ge2d_config->src2_para.fill_color_en;
#ifdef CONFIG_GE2D_SRC2
ge2d_cmd_cfg->src2_cmult_ad = ge2d_config->src2_cmult_ad;
#endif
ge2d_cmd_cfg->vsc_phase_slope = ge2d_config->vsc_phase_slope;
ge2d_cmd_cfg->vsc_ini_phase = ge2d_config->vf_init_phase;
ge2d_cmd_cfg->vsc_phase_step = ge2d_config->vsc_start_phase_step;
ge2d_cmd_cfg->vsc_rpt_l0_num = ge2d_config->vf_rpt_num;
/* let internal decide */
ge2d_cmd_cfg->hsc_phase_slope = ge2d_config->hsc_phase_slope;
ge2d_cmd_cfg->hsc_ini_phase = ge2d_config->hf_init_phase;
ge2d_cmd_cfg->hsc_phase_step = ge2d_config->hsc_start_phase_step;
ge2d_cmd_cfg->hsc_rpt_p0_num = ge2d_config->hf_rpt_num;
ge2d_cmd_cfg->src1_cmult_asel = ge2d_config->src1_cmult_asel;
ge2d_cmd_cfg->src2_cmult_asel = ge2d_config->src2_cmult_asel;
context->config.update_flag = UPDATE_ALL;
/* context->config.src1_data.ddr_burst_size_y = 3; */
/* context->config.src1_data.ddr_burst_size_cb = 3; */
/* context->config.src1_data.ddr_burst_size_cr = 3; */
/* context->config.src2_dst_data.ddr_burst_size= 3; */
return 0;
}
int ge2d_buffer_alloc(struct ge2d_dmabuf_req_s *ge2d_req_buf)
{
struct device *dev;
dev = &(ge2d_manager.pdev->dev);
return ge2d_dma_buffer_alloc(ge2d_manager.buffer,
dev, ge2d_req_buf);
}
int ge2d_buffer_export(struct ge2d_dmabuf_exp_s *ge2d_exp_buf)
{
return ge2d_dma_buffer_export(ge2d_manager.buffer, ge2d_exp_buf);
}
int ge2d_buffer_free(int index)
{
return ge2d_dma_buffer_free(ge2d_manager.buffer, index);
}
void ge2d_buffer_dma_flush(int dma_fd)
{
struct device *dev;
dev = &(ge2d_manager.pdev->dev);
ge2d_dma_buffer_dma_flush(dev, dma_fd);
}
void ge2d_buffer_cache_flush(int dma_fd)
{
struct device *dev;
dev = &(ge2d_manager.pdev->dev);
ge2d_dma_buffer_cache_flush(dev, dma_fd);
}
struct ge2d_context_s *create_ge2d_work_queue(void)
{
int i;
@@ -1933,6 +2565,9 @@ int ge2d_wq_init(struct platform_device *pdev,
INIT_LIST_HEAD(&ge2d_manager.process_queue);
ge2d_manager.last_wq = NULL;
ge2d_manager.ge2d_thread = NULL;
ge2d_manager.buffer = ge2d_dma_buffer_create();
if (!ge2d_manager.buffer)
return -1;
ge2d_clk_config(true);
ge2d_soft_rst();
ge2d_gen_cfg.interrupt_ctrl = 0x02;
@@ -1966,6 +2601,8 @@ int ge2d_wq_deinit(void)
}
ge2d_irq = -1;
clk_disable_unprepare(ge2d_clk);
ge2d_dma_buffer_destroy(ge2d_manager.buffer);
ge2d_manager.buffer = NULL;
ge2d_manager.pdev = NULL;
return 0;
}

View File

@@ -34,4 +34,9 @@ extern int ge2d_wq_init(struct platform_device *pdev,
int irq, struct clk *clk);
extern int ge2d_wq_deinit(void);
int ge2d_buffer_alloc(struct ge2d_dmabuf_req_s *ge2d_req_buf);
int ge2d_buffer_free(int index);
int ge2d_buffer_export(struct ge2d_dmabuf_exp_s *ge2d_exp_buf);
void ge2d_buffer_dma_flush(int dma_fd);
void ge2d_buffer_cache_flush(int dma_fd);
#endif

View File

@@ -27,6 +27,12 @@
#include <linux/compat.h>
#endif
enum ge2d_memtype_s {
AML_GE2D_MEM_ION,
AML_GE2D_MEM_DMABUF,
AML_GE2D_MEM_INVALID,
};
#define MAX_BITBLT_WORK_CONFIG 4
#define MAX_GE2D_CMD 32 /* 64 */
@@ -610,6 +616,12 @@ struct ge2d_config_s {
unsigned int update_flag;
};
struct ge2d_dma_buf_s {
dma_addr_t paddr;
void *vaddr;
int len;
};
enum ge2d_src_dst_e {
OSD0_OSD0 = 0,
OSD0_OSD1,
@@ -663,6 +675,7 @@ struct ge2d_manager_s {
struct ge2d_context_s *last_wq;
struct task_struct *ge2d_thread;
struct ge2d_event_s event;
struct aml_dma_buffer *buffer;
int irq_num;
int ge2d_state;
int process_queue_state;
@@ -949,6 +962,56 @@ struct compat_config_para_ex_ion_s {
struct compat_config_planes_ion_s dst_planes[4];
};
#endif
struct config_para_ex_memtype_s {
int ge2d_magic;
struct config_para_ex_ion_s _ge2d_config_ex;
/* memtype*/
unsigned int src1_mem_alloc_type;
unsigned int src2_mem_alloc_type;
unsigned int dst_mem_alloc_type;
};
struct config_ge2d_para_ex_s {
union {
struct config_para_ex_ion_s para_config_ion;
struct config_para_ex_memtype_s para_config_memtype;
};
};
#ifdef CONFIG_COMPAT
struct compat_config_para_ex_memtype_s {
int ge2d_magic;
struct compat_config_para_ex_ion_s _ge2d_config_ex;
/* memtype*/
unsigned int src1_mem_alloc_type;
unsigned int src2_mem_alloc_type;
unsigned int dst_mem_alloc_type;
};
struct compat_config_ge2d_para_ex_s {
union {
struct compat_config_para_ex_ion_s para_config_ion;
struct compat_config_para_ex_memtype_s para_config_memtype;
};
};
#endif
/* for ge2d dma buf define */
struct ge2d_dmabuf_req_s {
int index;
unsigned int len;
unsigned int dma_dir;
};
struct ge2d_dmabuf_exp_s {
int index;
unsigned int flags;
int fd;
};
/* end of ge2d dma buffer define */
struct ge2d_device_data_s {
int ge2d_rate;
int src2_alp;
@@ -990,6 +1053,21 @@ extern struct ge2d_device_data_s ge2d_meson_dev;
_IOW(GE2D_IOC_MAGIC, 0x03, struct compat_config_para_ex_ion_s)
#endif
#define GE2D_REQUEST_BUFF _IOW(GE2D_IOC_MAGIC, 0x04, struct ge2d_dmabuf_req_s)
#define GE2D_EXP_BUFF _IOW(GE2D_IOC_MAGIC, 0x05, struct ge2d_dmabuf_exp_s)
#define GE2D_FREE_BUFF _IOW(GE2D_IOC_MAGIC, 0x06, int)
#define GE2D_CONFIG_EX_MEM \
_IOW(GE2D_IOC_MAGIC, 0x07, struct config_ge2d_para_ex_s)
#ifdef CONFIG_COMPAT
#define GE2D_CONFIG_EX32_MEM \
_IOW(GE2D_IOC_MAGIC, 0x07, struct compat_config_ge2d_para_ex_s)
#endif
#define GE2D_SYNC_DEVICE _IOW(GE2D_IOC_MAGIC, 0x08, int)
#define GE2D_SYNC_CPU _IOW(GE2D_IOC_MAGIC, 0x09, int)
extern void ge2d_set_src1_data(struct ge2d_src1_data_s *cfg);
extern void ge2d_set_src1_gen(struct ge2d_src1_gen_s *cfg);
extern void ge2d_set_src2_dst_data(struct ge2d_src2_dst_data_s *cfg);
@@ -1010,6 +1088,8 @@ extern int ge2d_context_config_ex(struct ge2d_context_s *context,
struct config_para_ex_s *ge2d_config);
extern int ge2d_context_config_ex_ion(struct ge2d_context_s *context,
struct config_para_ex_ion_s *ge2d_config);
extern int ge2d_context_config_ex_mem(struct ge2d_context_s *context,
struct config_para_ex_memtype_s *ge2d_config_mem);
extern struct ge2d_context_s *create_ge2d_work_queue(void);
extern int destroy_ge2d_work_queue(struct ge2d_context_s *wq);
extern int ge2d_wq_remove_config(struct ge2d_context_s *wq);