gdc: add a convert function to map dma address [1/1]

PD#SWPL-2157

Problem:
gdc module need to get dma address directly

Solution:
add a convert function to map dma address

Verify:
g12b

Change-Id: I1d40350e4727335d1f69f38caafb1dfe7b0db842
Signed-off-by: Keke Li <keke.li@amlogic.com>
This commit is contained in:
keke.li
2018-11-27 13:54:21 +08:00
committed by Dongjin Kim
parent af134581f8
commit be69aacb33
3 changed files with 237 additions and 1 deletions

View File

@@ -31,7 +31,7 @@
#include <linux/dma-mapping.h>
#include <linux/dma-contiguous.h>
#include <linux/of_reserved_mem.h>
#include <linux/dma-buf.h>
#include <linux/of_address.h>
#include <api/gdc_api.h>
@@ -273,6 +273,216 @@ static void meson_gdc_cache_flush(struct device *dev,
dma_sync_single_for_cpu(dev, addr, size, DMA_FROM_DEVICE);
}
static long meson_gdc_dma_map(struct gdc_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) {
LOG(LOG_ERR, "Error input param");
return -EINVAL;
}
fd = cfg->fd;
dev = cfg->dev;
dir = cfg->dir;
dbuf = dma_buf_get(fd);
if (dbuf == NULL) {
LOG(LOG_ERR, "Failed to get dma buffer");
return -EINVAL;
}
d_att = dma_buf_attach(dbuf, dev);
if (d_att == NULL) {
LOG(LOG_ERR, "Failed to set dma attach");
goto attach_err;
}
sg = dma_buf_map_attachment(d_att, dir);
if (sg == NULL) {
LOG(LOG_ERR, "Failed to get dma sg");
goto map_attach_err;
}
ret = dma_buf_begin_cpu_access(dbuf, dir);
if (ret != 0) {
LOG(LOG_ERR, "Failed to access dma buff");
goto access_err;
}
vaddr = dma_buf_vmap(dbuf);
if (vaddr == NULL) {
LOG(LOG_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;
}
static void meson_gdc_dma_unmap(struct gdc_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) {
LOG(LOG_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);
}
static long meson_gdc_init_dma_addr(struct gdc_settings *gs)
{
long ret = -1;
struct gdc_dma_cfg *dma_cfg = NULL;
struct gdc_config *gc = NULL;
struct mgdc_fh_s *fh = NULL;
if (gs == NULL || gs->fh == NULL) {
LOG(LOG_ERR, "Error input param\n");
return -EINVAL;
}
gc = &gs->gdc_config;
fh = gs->fh;
switch (gc->format) {
case NV12:
dma_cfg = &fh->y_dma_cfg;
memset(dma_cfg, 0, sizeof(*dma_cfg));
dma_cfg->dir = DMA_TO_DEVICE;
dma_cfg->dev = &fh->gdev->pdev->dev;
dma_cfg->fd = gs->y_base_fd;
ret = meson_gdc_dma_map(dma_cfg);
if (ret != 0) {
LOG(LOG_ERR, "Failed to get map dma buff");
return ret;
}
gs->y_base_addr = virt_to_phys(dma_cfg->vaddr);
dma_cfg = &fh->uv_dma_cfg;
memset(dma_cfg, 0, sizeof(*dma_cfg));
dma_cfg->dir = DMA_TO_DEVICE;
dma_cfg->dev = &fh->gdev->pdev->dev;
dma_cfg->fd = gs->uv_base_fd;
ret = meson_gdc_dma_map(dma_cfg);
if (ret != 0) {
LOG(LOG_ERR, "Failed to get map dma buff");
return ret;
}
gs->uv_base_addr = virt_to_phys(dma_cfg->vaddr);
break;
case Y_GREY:
dma_cfg = &fh->y_dma_cfg;
memset(dma_cfg, 0, sizeof(*dma_cfg));
dma_cfg->dir = DMA_TO_DEVICE;
dma_cfg->dev = &fh->gdev->pdev->dev;
dma_cfg->fd = gs->y_base_fd;
ret = meson_gdc_dma_map(dma_cfg);
if (ret != 0) {
LOG(LOG_ERR, "Failed to get map dma buff");
return ret;
}
gs->y_base_addr = virt_to_phys(dma_cfg->vaddr);
gs->uv_base_addr = 0;
break;
default:
LOG(LOG_ERR, "Error image format");
break;
}
return ret;
}
static void meson_gdc_deinit_dma_addr(struct gdc_settings *gs)
{
struct gdc_dma_cfg *dma_cfg = NULL;
struct gdc_config *gc = NULL;
struct mgdc_fh_s *fh = NULL;
if (gs == NULL || gs->fh == NULL) {
LOG(LOG_ERR, "Error input param\n");
return;
}
gc = &gs->gdc_config;
fh = gs->fh;
switch (gc->format) {
case NV12:
dma_cfg = &fh->y_dma_cfg;
meson_gdc_dma_unmap(dma_cfg);
dma_cfg = &fh->uv_dma_cfg;
meson_gdc_dma_unmap(dma_cfg);
break;
case Y_GREY:
dma_cfg = &fh->y_dma_cfg;
meson_gdc_dma_unmap(dma_cfg);
break;
default:
LOG(LOG_ERR, "Error image format");
break;
}
}
static long meson_gdc_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
@@ -404,6 +614,12 @@ static long meson_gdc_ioctl(struct file *file, unsigned int cmd,
gs->fh = fh;
mutex_lock(&fh->gdev->d_mutext);
ret = meson_gdc_init_dma_addr(gs);
if (ret != 0) {
mutex_unlock(&fh->gdev->d_mutext);
LOG(LOG_ERR, "Failed to init dma addr");
return ret;
}
meson_gdc_dma_flush(&fh->gdev->pdev->dev,
fh->c_paddr, fh->c_len);
ret = gdc_run(gs);
@@ -418,6 +634,7 @@ static long meson_gdc_ioctl(struct file *file, unsigned int cmd,
gdc_stop(gs);
meson_gdc_cache_flush(&fh->gdev->pdev->dev,
fh->o_paddr, fh->o_len);
meson_gdc_deinit_dma_addr(gs);
mutex_unlock(&fh->gdev->d_mutext);
break;
case GDC_REQUEST_BUFF:

View File

@@ -19,6 +19,7 @@
#define __GDC_API_H__
#include <linux/of_address.h>
#include <linux/dma-direction.h>
struct gdc_buf_cfg {
uint32_t type;
@@ -79,6 +80,12 @@ struct gdc_settings {
uint32_t y_line_offset,
uint32_t uv_line_offset);
void *fh;
int32_t y_base_fd;
union {
int32_t uv_base_fd;
int32_t u_base_fd;
};
int32_t v_base_fd;
};
#define GDC_IOC_MAGIC 'G'
@@ -104,6 +111,16 @@ enum {
FMT_MAX
};
struct gdc_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;
};
/**
* Configure the output gdc configuration
*

View File

@@ -54,6 +54,8 @@ struct mgdc_fh_s {
unsigned long i_len;
unsigned long o_len;
unsigned long c_len;
struct gdc_dma_cfg y_dma_cfg;
struct gdc_dma_cfg uv_dma_cfg;
};
irqreturn_t interrupt_handler_next(int irq, void *param);