101 lines
2.6 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Rockchip Flexbus CIF Driver
*
* Copyright (C) 2024 Rockchip Electronics Co., Ltd.
*/
#include <media/videobuf2-cma-sg.h>
#include <media/videobuf2-dma-contig.h>
#include <linux/of_platform.h>
#include "dev.h"
#include "common.h"
MODULE_IMPORT_NS(DMA_BUF);
static void flexbus_cif_init_dummy_vb2(struct flexbus_cif_device *dev,
struct flexbus_cif_dummy_buffer *buf)
{
unsigned long attrs = buf->is_need_vaddr ? 0 : DMA_ATTR_NO_KERNEL_MAPPING;
memset(&buf->vb2_queue, 0, sizeof(struct vb2_queue));
memset(&buf->vb, 0, sizeof(struct vb2_buffer));
buf->vb2_queue.gfp_flags = GFP_KERNEL | GFP_DMA32;
buf->vb2_queue.dma_dir = DMA_BIDIRECTIONAL;
attrs |= DMA_ATTR_FORCE_CONTIGUOUS;
buf->vb2_queue.dma_attrs = attrs;
buf->vb.vb2_queue = &buf->vb2_queue;
}
int flexbus_cif_alloc_buffer(struct flexbus_cif_device *dev,
struct flexbus_cif_dummy_buffer *buf)
{
const struct vb2_mem_ops *g_ops = &vb2_cma_sg_memops;
struct sg_table *sg_tbl;
void *mem_priv;
int ret = 0;
if (!buf->size) {
ret = -EINVAL;
goto err;
}
flexbus_cif_init_dummy_vb2(dev, buf);
buf->size = PAGE_ALIGN(buf->size);
mem_priv = g_ops->alloc(&buf->vb, dev->dev, buf->size);
if (IS_ERR_OR_NULL(mem_priv)) {
ret = -ENOMEM;
goto err;
}
buf->mem_priv = mem_priv;
sg_tbl = (struct sg_table *)g_ops->cookie(&buf->vb, mem_priv);
buf->dma_addr = sg_dma_address(sg_tbl->sgl);
g_ops->prepare(mem_priv);
if (buf->is_need_vaddr)
buf->vaddr = g_ops->vaddr(&buf->vb, mem_priv);
if (buf->is_need_dbuf) {
buf->dbuf = g_ops->get_dmabuf(&buf->vb, mem_priv, O_RDWR);
if (buf->is_need_dmafd) {
buf->dma_fd = dma_buf_fd(buf->dbuf, O_CLOEXEC);
if (buf->dma_fd < 0) {
dma_buf_put(buf->dbuf);
ret = buf->dma_fd;
goto err;
}
get_dma_buf(buf->dbuf);
}
}
v4l2_dbg(1, flexbus_cif_debug, &dev->v4l2_dev,
"%s buf:0x%x~0x%x size:%d\n", __func__,
(u32)buf->dma_addr, (u32)buf->dma_addr + buf->size, buf->size);
return ret;
err:
dev_err(dev->dev, "%s failed ret:%d\n", __func__, ret);
return ret;
}
void flexbus_cif_free_buffer(struct flexbus_cif_device *dev,
struct flexbus_cif_dummy_buffer *buf)
{
const struct vb2_mem_ops *g_ops = &vb2_cma_sg_memops;
if (buf && buf->mem_priv) {
v4l2_dbg(1, flexbus_cif_debug, &dev->v4l2_dev,
"%s buf:0x%x~0x%x\n", __func__,
(u32)buf->dma_addr, (u32)buf->dma_addr + buf->size);
if (buf->dbuf)
dma_buf_put(buf->dbuf);
g_ops->put(buf->mem_priv);
buf->size = 0;
buf->dbuf = NULL;
buf->vaddr = NULL;
buf->mem_priv = NULL;
buf->is_need_dbuf = false;
buf->is_need_vaddr = false;
buf->is_need_dmafd = false;
buf->is_free = true;
}
}