media: rockchip: ispp: use fec share buffer to reduce buffer size

Signed-off-by: Hu Kejun <william.hu@rock-chips.com>
Change-Id: Ie59ce6dbedbbc1a60d5eb3e8a4216b2f4869140d
This commit is contained in:
Hu Kejun
2020-10-03 11:11:19 +08:00
committed by Tao Huang
parent 7dfb03af68
commit 54e1a2cf73
8 changed files with 239 additions and 69 deletions

View File

@@ -87,8 +87,18 @@ int rkispp_allow_buffer(struct rkispp_device *dev,
buf->dma_addr = *((dma_addr_t *)g_ops->cookie(mem_priv));
if (!attrs)
buf->vaddr = g_ops->vaddr(mem_priv);
if (buf->is_need_dbuf)
if (buf->is_need_dbuf) {
buf->dbuf = g_ops->get_dmabuf(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, rkispp_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);
@@ -114,6 +124,7 @@ void rkispp_free_buffer(struct rkispp_device *dev,
buf->mem_priv = NULL;
buf->is_need_dbuf = false;
buf->is_need_vaddr = false;
buf->is_need_dmafd = false;
}
}

View File

@@ -68,8 +68,10 @@ struct rkispp_dummy_buffer {
u64 timestamp;
u32 size;
u32 id;
int dma_fd;
bool is_need_vaddr;
bool is_need_dbuf;
bool is_need_dmafd;
};
static inline struct rkispp_vdev_node *vdev_to_node(struct video_device *vdev)

View File

@@ -361,6 +361,64 @@ static int rkispp_sd_s_power(struct v4l2_subdev *sd, int on)
return ret;
}
static long rkispp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
struct rkispp_device *ispp_dev = ispp_sdev->dev;
struct rkispp_fecbuf_info *fecbuf;
struct rkispp_fecbuf_size *fecsize;
long ret = 0;
if (!arg)
return -EINVAL;
switch (cmd) {
case RKISPP_CMD_GET_FECBUF_INFO:
fecbuf = (struct rkispp_fecbuf_info *)arg;
rkispp_params_get_fecbuf_inf(&ispp_dev->params_vdev, fecbuf);
break;
case RKISPP_CMD_SET_FECBUF_SIZE:
fecsize = (struct rkispp_fecbuf_size *)arg;
rkispp_params_set_fecbuf_size(&ispp_dev->params_vdev, fecsize);
break;
default:
ret = -ENOIOCTLCMD;
}
return ret;
}
#ifdef CONFIG_COMPAT
static long rkispp_compat_ioctl32(struct v4l2_subdev *sd,
unsigned int cmd, unsigned long arg)
{
void __user *up = compat_ptr(arg);
struct rkispp_fecbuf_info fecbuf;
struct rkispp_fecbuf_size fecsize;
long ret = 0;
if (!up)
return -EINVAL;
switch (cmd) {
case RKISPP_CMD_GET_FECBUF_INFO:
ret = rkispp_ioctl(sd, cmd, &fecbuf);
if (!ret)
ret = copy_to_user(up, &fecbuf, sizeof(fecbuf));
break;
case RKISPP_CMD_SET_FECBUF_SIZE:
ret = copy_from_user(&fecsize, up, sizeof(fecsize));
if (!ret)
ret = rkisp_ioctl(sd, cmd, &fecsize);
break;
default:
ret = -ENOIOCTLCMD;
}
return ret;
}
#endif
static const struct media_entity_operations rkispp_sd_media_ops = {
.link_setup = rkispp_subdev_link_setup,
.link_validate = v4l2_subdev_link_validate,
@@ -380,6 +438,10 @@ static const struct v4l2_subdev_video_ops rkispp_sd_video_ops = {
static const struct v4l2_subdev_core_ops rkispp_sd_core_ops = {
.s_power = rkispp_sd_s_power,
.ioctl = rkispp_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = rkispp_compat_ioctl32,
#endif
};
static struct v4l2_subdev_ops rkispp_sd_ops = {

View File

@@ -529,17 +529,54 @@ static void fec_config(struct rkispp_params_vdev *params_vdev,
struct rkispp_fec_config *arg)
{
struct rkispp_device *dev = params_vdev->dev;
struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
struct rkispp_dummy_buffer *buf;
u32 val;
struct rkispp_fec_head *fec_data;
u32 width, height, mesh_size;
dma_addr_t dma_addr;
u32 val, i, buf_idx;
if (arg->mesh_size > vdev->fec_buf.mesh_xint.size) {
width = dev->ispp_sdev.out_fmt.width;
height = dev->ispp_sdev.out_fmt.height;
mesh_size = cal_fec_mesh(width, height, 0);
if (arg->mesh_size > mesh_size) {
v4l2_err(&dev->v4l2_dev,
"Input mesh size too large. mesh size 0x%x, 0x%x\n",
arg->mesh_size, vdev->fec_buf.mesh_xint.size);
arg->mesh_size, mesh_size);
return;
}
for (i = 0; i < FEC_MESH_BUF_NUM; i++) {
if (arg->buf_fd == params_vdev->buf_fec[i].dma_fd)
break;
}
if (i == FEC_MESH_BUF_NUM) {
dev_err(dev->dev, "cannot find fec buf fd(%d)\n", arg->buf_fd);
return;
}
if (!params_vdev->buf_fec[i].vaddr) {
dev_err(dev->dev, "no fec buffer allocated\n");
return;
}
buf_idx = params_vdev->buf_fec_idx;
fec_data = (struct rkispp_fec_head *)params_vdev->buf_fec[buf_idx].vaddr;
fec_data->stat = FEC_BUF_INIT;
buf_idx = i;
fec_data = (struct rkispp_fec_head *)params_vdev->buf_fec[buf_idx].vaddr;
fec_data->stat = FEC_BUF_CHIPINUSE;
params_vdev->buf_fec_idx = buf_idx;
dma_addr = params_vdev->buf_fec[buf_idx].dma_addr;
val = dma_addr + fec_data->meshxf_oft;
rkispp_write(params_vdev->dev, RKISPP_FEC_MESH_XFRA_BASE, val);
val = dma_addr + fec_data->meshyf_oft;
rkispp_write(params_vdev->dev, RKISPP_FEC_MESH_YFRA_BASE, val);
val = dma_addr + fec_data->meshxi_oft;
rkispp_write(params_vdev->dev, RKISPP_FEC_MESH_XINT_BASE, val);
val = dma_addr + fec_data->meshyi_oft;
rkispp_write(params_vdev->dev, RKISPP_FEC_MESH_YINT_BASE, val);
val = 0;
if (arg->mesh_density)
val = SW_MESH_DENSITY;
@@ -550,20 +587,19 @@ static void fec_config(struct rkispp_params_vdev *params_vdev,
val = (arg->crop_height & 0x1FFFF) << 14 |
(arg->crop_width & 0x1FFFF) << 1 | (arg->crop_en & 0x01);
rkispp_write(params_vdev->dev, RKISPP_FEC_CROP, val);
buf = &vdev->fec_buf.mesh_xint;
memcpy(buf->vaddr, &arg->meshxi[0], arg->mesh_size * sizeof(u16));
buf = &vdev->fec_buf.mesh_yint;
memcpy(buf->vaddr, &arg->meshyi[0], arg->mesh_size * sizeof(u16));
buf = &vdev->fec_buf.mesh_xfra;
memcpy(buf->vaddr, &arg->meshxf[0], arg->mesh_size * sizeof(u8));
buf = &vdev->fec_buf.mesh_yfra;
memcpy(buf->vaddr, &arg->meshyf[0], arg->mesh_size * sizeof(u8));
}
static void fec_enable(struct rkispp_params_vdev *params_vdev, bool en)
{
struct rkispp_device *dev = params_vdev->dev;
u32 buf_idx;
if (en) {
buf_idx = params_vdev->buf_fec_idx;
if (!params_vdev->buf_fec[buf_idx].vaddr) {
dev_err(dev->dev, "no fec buffer allocated\n");
return;
}
rkispp_clear_bits(params_vdev->dev, RKISPP_SCL0_CTRL, SW_SCL_FIRST_MODE);
rkispp_clear_bits(params_vdev->dev, RKISPP_SCL1_CTRL, SW_SCL_FIRST_MODE);
rkispp_clear_bits(params_vdev->dev, RKISPP_SCL2_CTRL, SW_SCL_FIRST_MODE);
@@ -683,6 +719,54 @@ static const struct v4l2_ioctl_ops rkispp_params_ioctl = {
.vidioc_unsubscribe_event = v4l2_event_unsubscribe
};
static int
rkispp_param_init_fecbuf(struct rkispp_params_vdev *params,
struct rkispp_fecbuf_size *fecsize)
{
struct rkispp_device *pp_dev = params->dev;
struct rkispp_fec_head *fec_data;
u32 width, height, mesh_size, buf_size;
int i, ret;
width = fecsize->meas_width;
height = fecsize->meas_height;
mesh_size = cal_fec_mesh(width, height, fecsize->meas_mode);
buf_size = ALIGN(sizeof(struct rkispp_fec_head), 16);
buf_size += 2 * (ALIGN(mesh_size * 2, 16) + ALIGN(mesh_size, 16));
params->buf_fec_idx = 0;
for (i = 0; i < FEC_MESH_BUF_NUM; i++) {
params->buf_fec[i].is_need_vaddr = true;
params->buf_fec[i].is_need_dbuf = true;
params->buf_fec[i].is_need_dmafd = true;
params->buf_fec[i].size = PAGE_ALIGN(buf_size);
ret = rkispp_allow_buffer(params->dev, &params->buf_fec[i]);
if (ret) {
dev_err(pp_dev->dev, "can not alloc fec buffer\n");
return ret;
}
fec_data = (struct rkispp_fec_head *)params->buf_fec[i].vaddr;
fec_data->stat = FEC_BUF_INIT;
fec_data->meshxf_oft = ALIGN(sizeof(struct rkispp_fec_head), 16);
fec_data->meshyf_oft = fec_data->meshxf_oft + ALIGN(mesh_size, 16);
fec_data->meshxi_oft = fec_data->meshyf_oft + ALIGN(mesh_size, 16);
fec_data->meshyi_oft = fec_data->meshxi_oft + ALIGN(mesh_size * 2, 16);
}
return 0;
}
static void
rkispp_param_deinit_fecbuf(struct rkispp_params_vdev *params)
{
int i;
params->buf_fec_idx = 0;
for (i = 0; i < FEC_MESH_BUF_NUM; i++)
rkispp_free_buffer(params->dev, &params->buf_fec[i]);
}
static int rkispp_params_vb2_queue_setup(struct vb2_queue *vq,
unsigned int *num_buffers,
unsigned int *num_planes,
@@ -803,9 +887,14 @@ rkispp_param_fh_open(struct file *filp)
if (ret < 0) {
v4l2_err(&isppdev->v4l2_dev,
"pipeline power on failed %d\n", ret);
vb2_fop_release(filp);
goto ERR;
}
}
return 0;
ERR:
vb2_fop_release(filp);
return ret;
}
@@ -823,6 +912,7 @@ rkispp_param_fh_release(struct file *filp)
v4l2_err(&isppdev->v4l2_dev,
"pipeline power off failed %d\n", ret);
}
rkispp_param_deinit_fecbuf(params);
return ret;
}
@@ -1060,6 +1150,24 @@ void rkispp_params_configure(struct rkispp_params_vdev *params_vdev)
!!(module_ens & ISPP_MODULE_ORB));
}
void rkispp_params_get_fecbuf_inf(struct rkispp_params_vdev *params_vdev,
struct rkispp_fecbuf_info *fecbuf)
{
int i;
for (i = 0; i < FEC_MESH_BUF_NUM; i++) {
fecbuf->buf_fd[i] = params_vdev->buf_fec[i].dma_fd;
fecbuf->buf_size[i] = params_vdev->buf_fec[i].size;
}
}
void rkispp_params_set_fecbuf_size(struct rkispp_params_vdev *params_vdev,
struct rkispp_fecbuf_size *fecsize)
{
rkispp_param_deinit_fecbuf(params_vdev);
rkispp_param_init_fecbuf(params_vdev, fecsize);
}
int rkispp_register_params_vdev(struct rkispp_device *dev)
{
struct rkispp_params_vdev *params_vdev = &dev->params_vdev;

View File

@@ -26,10 +26,17 @@ struct rkispp_params_vdev {
struct v4l2_format vdev_fmt;
bool streamon;
bool first_params;
struct rkispp_dummy_buffer buf_fec[FEC_MESH_BUF_NUM];
u32 buf_fec_idx;
};
int rkispp_register_params_vdev(struct rkispp_device *dev);
void rkispp_unregister_params_vdev(struct rkispp_device *dev);
void rkispp_params_configure(struct rkispp_params_vdev *params_vdev);
void rkispp_params_isr(struct rkispp_params_vdev *params_vdev, u32 mis);
void rkispp_params_get_fecbuf_inf(struct rkispp_params_vdev *params_vdev,
struct rkispp_fecbuf_info *fecbuf);
void rkispp_params_set_fecbuf_size(struct rkispp_params_vdev *params_vdev,
struct rkispp_fecbuf_size *fecsize);
#endif

View File

@@ -824,26 +824,18 @@ static void fec_free_buf(struct rkispp_device *dev)
{
struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
struct list_head *list = &vdev->fec.list_rd;
int i;
if (vdev->fec.cur_rd)
vdev->fec.cur_rd = NULL;
while (!list_empty(list))
get_list_buf(list, false);
for (i = 0; i < sizeof(vdev->fec_buf) /
sizeof(struct rkispp_dummy_buffer); i++)
rkispp_free_buffer(dev, &vdev->fec_buf.mesh_xint + i);
}
static int config_fec(struct rkispp_device *dev)
{
struct rkispp_stream_vdev *vdev;
struct rkispp_stream *stream = NULL;
struct rkispp_dummy_buffer *buf;
u32 width, height, fmt, mult = 1;
u32 mesh_size;
int ret;
vdev = &dev->stream_vdev;
vdev->fec.is_end = true;
@@ -876,39 +868,6 @@ static int config_fec(struct rkispp_device *dev)
stream->config->reg.cur_uv_base_shd = RKISPP_FEC_RD_UV_BASE_SHD;
}
mesh_size = cal_fec_mesh(width, height, 0);
buf = &vdev->fec_buf.mesh_xint;
buf->is_need_vaddr = true;
buf->size = ALIGN(mesh_size * 2, 8);
ret = rkispp_allow_buffer(dev, buf);
if (ret < 0)
goto err;
rkispp_write(dev, RKISPP_FEC_MESH_XINT_BASE, buf->dma_addr);
buf = &vdev->fec_buf.mesh_yint;
buf->is_need_vaddr = true;
buf->size = ALIGN(mesh_size * 2, 8);
ret = rkispp_allow_buffer(dev, buf);
if (ret < 0)
goto err;
rkispp_write(dev, RKISPP_FEC_MESH_YINT_BASE, buf->dma_addr);
buf = &vdev->fec_buf.mesh_xfra;
buf->is_need_vaddr = true;
buf->size = ALIGN(mesh_size, 8);
ret = rkispp_allow_buffer(dev, buf);
if (ret < 0)
goto err;
rkispp_write(dev, RKISPP_FEC_MESH_XFRA_BASE, buf->dma_addr);
buf = &vdev->fec_buf.mesh_yfra;
buf->is_need_vaddr = true;
buf->size = ALIGN(mesh_size, 8);
ret = rkispp_allow_buffer(dev, buf);
if (ret < 0)
goto err;
rkispp_write(dev, RKISPP_FEC_MESH_YFRA_BASE, buf->dma_addr);
rkispp_set_bits(dev, RKISPP_FEC_CTRL, FMT_RD_MASK, fmt);
rkispp_write(dev, RKISPP_FEC_RD_VIR_STRIDE, ALIGN(width * mult, 16) >> 2);
rkispp_write(dev, RKISPP_FEC_PIC_SIZE, height << 16 | width);
@@ -919,11 +878,6 @@ static int config_fec(struct rkispp_device *dev)
rkispp_read(dev, RKISPP_FEC_CTRL),
rkispp_read(dev, RKISPP_FEC_CORE_CTRL));
return 0;
err:
fec_free_buf(dev);
v4l2_err(&dev->v4l2_dev,
"%s Failed to allocate buffer\n", __func__);
return ret;
}
static void rkispp_start_3a_run(struct rkispp_device *dev)

View File

@@ -207,7 +207,6 @@ struct rkispp_stream_vdev {
struct tnr_module tnr;
struct nr_module nr;
struct fec_module fec;
struct in_fec_buf fec_buf;
struct frame_debug_info dbg;
struct rkispp_monitor monitor;
atomic_t refcnt;

View File

@@ -72,6 +72,13 @@
#define FEC_MESH_XY_POINT_SIZE 6
#define FEC_MESH_XY_NUM 131072
#define FEC_MESH_BUF_NUM 2
#define RKISPP_CMD_GET_FECBUF_INFO \
_IOR('V', BASE_VIDIOC_PRIVATE + 0, struct rkispp_fecbuf_info)
#define RKISPP_CMD_SET_FECBUF_SIZE \
_IOW('V', BASE_VIDIOC_PRIVATE + 1, struct rkispp_fecbuf_size)
struct rkispp_tnr_config {
u8 opty_en;
@@ -215,18 +222,38 @@ struct rkispp_sharp_config {
u16 rfh_ratio;
} __attribute__ ((packed));
enum rkispp_fecbuf_stat {
FEC_BUF_INIT = 0,
FEC_BUF_WAIT2CHIP,
FEC_BUF_CHIPINUSE,
};
struct rkispp_fecbuf_info {
s32 buf_fd[FEC_MESH_BUF_NUM];
u32 buf_size[FEC_MESH_BUF_NUM];
} __attribute__ ((packed));
struct rkispp_fecbuf_size {
u32 meas_width;
u32 meas_height;
u32 meas_mode;
} __attribute__ ((packed));
struct rkispp_fec_head {
enum rkispp_fecbuf_stat stat;
u32 meshxf_oft;
u32 meshyf_oft;
u32 meshxi_oft;
u32 meshyi_oft;
} __attribute__ ((packed));
struct rkispp_fec_config {
u8 mesh_density;
u8 crop_en;
u8 meshxf[FEC_MESH_XY_NUM];
u8 meshyf[FEC_MESH_XY_NUM];
u16 crop_width __attribute__((aligned(2)));
u16 crop_height;
u16 meshxi[FEC_MESH_XY_NUM];
u16 meshyi[FEC_MESH_XY_NUM];
u32 mesh_size __attribute__((aligned(4)));
s32 buf_fd;
} __attribute__ ((packed));
struct rkispp_orb_config {