media: rockchip: vicap use tasklet to done buf

when buffer needs to refresh the cache, which takes a lot of time and
is not suitable for execution in an interrupt

Signed-off-by: Zefa Chen <zefa.chen@rock-chips.com>
Change-Id: I6b6e54cef62711787430b1b336db3476e3f93e69
This commit is contained in:
Zefa Chen
2022-07-14 20:36:48 +08:00
committed by Tao Huang
parent c69ef7e2ae
commit 824a24f406
2 changed files with 93 additions and 56 deletions

View File

@@ -4224,6 +4224,8 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream,
if (can_reset && hw_dev->dummy_buf.vaddr)
rkcif_destroy_dummy_buf(stream);
stream->cur_stream_mode &= ~mode;
tasklet_disable(&stream->vb_done_tasklet);
INIT_LIST_HEAD(&stream->vb_done_list);
v4l2_info(&dev->v4l2_dev, "stream[%d] stopping finished, dma_en 0x%x\n", stream->id, stream->dma_en);
mutex_unlock(&dev->stream_lock);
rkcif_detach_sync_mode(dev);
@@ -5284,6 +5286,7 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode)
dev->reset_work_cancel = false;
stream->cur_stream_mode |= mode;
rkcif_monitor_reset_event(dev);
tasklet_enable(&stream->vb_done_tasklet);
goto out;
stop_stream:
@@ -6192,8 +6195,58 @@ static const struct v4l2_ioctl_ops rkcif_v4l2_ioctl_ops = {
.vidioc_default = rkcif_ioctl_default,
};
void rkcif_vb_done_oneframe(struct rkcif_stream *stream,
struct vb2_v4l2_buffer *vb_done)
{
const struct cif_output_fmt *fmt = stream->cif_fmt_out;
u32 i;
/* Dequeue a filled buffer */
for (i = 0; i < fmt->mplanes; i++) {
vb2_set_plane_payload(&vb_done->vb2_buf, i,
stream->pixm.plane_fmt[i].sizeimage);
}
vb2_buffer_done(&vb_done->vb2_buf, VB2_BUF_STATE_DONE);
v4l2_dbg(2, rkcif_debug, &stream->cifdev->v4l2_dev,
"stream[%d] vb done, index: %d, sequence %d\n", stream->id,
vb_done->vb2_buf.index, vb_done->sequence);
}
static void rkcif_tasklet_handle(unsigned long data)
{
struct rkcif_stream *stream = (struct rkcif_stream *)data;
struct rkcif_buffer *buf = NULL;
unsigned long flags = 0;
LIST_HEAD(local_list);
spin_lock_irqsave(&stream->vbq_lock, flags);
list_replace_init(&stream->vb_done_list, &local_list);
spin_unlock_irqrestore(&stream->vbq_lock, flags);
while (!list_empty(&local_list)) {
buf = list_first_entry(&local_list,
struct rkcif_buffer, queue);
list_del(&buf->queue);
rkcif_vb_done_oneframe(stream, &buf->vb);
}
}
static void rkcif_vb_done_tasklet(struct rkcif_stream *stream, struct rkcif_buffer *buf)
{
unsigned long flags = 0;
if (!stream || !buf)
return;
spin_lock_irqsave(&stream->vbq_lock, flags);
list_add_tail(&buf->queue, &stream->vb_done_list);
spin_unlock_irqrestore(&stream->vbq_lock, flags);
tasklet_schedule(&stream->vb_done_tasklet);
}
static void rkcif_unregister_stream_vdev(struct rkcif_stream *stream)
{
tasklet_kill(&stream->vb_done_tasklet);
media_entity_cleanup(&stream->vnode.vdev.entity);
video_unregister_device(&stream->vnode.vdev);
}
@@ -6307,6 +6360,11 @@ static int rkcif_register_stream_vdev(struct rkcif_stream *stream,
if (ret < 0)
goto unreg;
INIT_LIST_HEAD(&stream->vb_done_list);
tasklet_init(&stream->vb_done_tasklet,
rkcif_tasklet_handle,
(unsigned long)stream);
tasklet_disable(&stream->vb_done_tasklet);
return 0;
unreg:
video_unregister_device(vdev);
@@ -6738,24 +6796,6 @@ void rkcif_unregister_dvp_sof_subdev(struct rkcif_device *dev)
v4l2_device_unregister_subdev(sd);
}
void rkcif_vb_done_oneframe(struct rkcif_stream *stream,
struct vb2_v4l2_buffer *vb_done)
{
const struct cif_output_fmt *fmt = stream->cif_fmt_out;
u32 i;
/* Dequeue a filled buffer */
for (i = 0; i < fmt->mplanes; i++) {
vb2_set_plane_payload(&vb_done->vb2_buf, i,
stream->pixm.plane_fmt[i].sizeimage);
}
vb2_buffer_done(&vb_done->vb2_buf, VB2_BUF_STATE_DONE);
v4l2_dbg(2, rkcif_debug, &stream->cifdev->v4l2_dev,
"stream[%d] vb done, index: %d, sequence %d, dma_en 0x%x\n", stream->id,
vb_done->vb2_buf.index, vb_done->sequence, stream->dma_en);
}
void rkcif_irq_oneframe(struct rkcif_device *cif_dev)
{
/* TODO: xuhf-debug: add stream type */
@@ -6787,7 +6827,7 @@ void rkcif_irq_oneframe(struct rkcif_device *cif_dev)
}
if ((intstat & FRAME_END)) {
struct vb2_v4l2_buffer *vb_done = NULL;
struct rkcif_buffer *active_buf = NULL;
rkcif_write_register(cif_dev, CIF_REG_DVP_INTSTAT,
FRAME_END_CLR);
@@ -6820,11 +6860,11 @@ void rkcif_irq_oneframe(struct rkcif_device *cif_dev)
if (frmid % 2 != 0) {
stream->frame_phase = CIF_CSI_FRAME0_READY;
if (stream->curr_buf)
vb_done = &stream->curr_buf->vb;
active_buf = stream->curr_buf;
} else {
stream->frame_phase = CIF_CSI_FRAME1_READY;
if (stream->next_buf)
vb_done = &stream->next_buf->vb;
active_buf = stream->next_buf;
}
/* In one-frame mode:
@@ -6837,9 +6877,9 @@ void rkcif_irq_oneframe(struct rkcif_device *cif_dev)
ret = rkcif_assign_new_buffer_oneframe(stream,
RKCIF_YUV_ADDR_STATE_UPDATE);
if (vb_done && (!ret)) {
vb_done->sequence = stream->frame_idx - 1;
rkcif_vb_done_oneframe(stream, vb_done);
if (active_buf && (!ret)) {
active_buf->vb.sequence = stream->frame_idx - 1;
rkcif_vb_done_tasklet(stream, active_buf);
}
cif_dev->irq_stats.all_frm_end_cnt++;
@@ -7366,16 +7406,13 @@ static void rkcif_rdbk_frame_end(struct rkcif_stream *stream)
if (!work_busy(&dev->stream[i].tools_vdev->tools_work.work))
schedule_work(&dev->stream[i].tools_vdev->tools_work.work);
else
rkcif_vb_done_oneframe(&dev->stream[i], &dev->rdbk_buf[i]->vb);
rkcif_vb_done_tasklet(&dev->stream[i], dev->rdbk_buf[i]);
spin_unlock_irqrestore(&dev->stream[i].tools_vdev->vbq_lock, flags);
}
} else {
rkcif_vb_done_oneframe(&dev->stream[RKCIF_STREAM_MIPI_ID0],
&dev->rdbk_buf[RDBK_L]->vb);
rkcif_vb_done_oneframe(&dev->stream[RKCIF_STREAM_MIPI_ID1],
&dev->rdbk_buf[RDBK_M]->vb);
rkcif_vb_done_oneframe(&dev->stream[RKCIF_STREAM_MIPI_ID2],
&dev->rdbk_buf[RDBK_S]->vb);
rkcif_vb_done_tasklet(&dev->stream[RKCIF_STREAM_MIPI_ID0], dev->rdbk_buf[RDBK_L]);
rkcif_vb_done_tasklet(&dev->stream[RKCIF_STREAM_MIPI_ID1], dev->rdbk_buf[RDBK_M]);
rkcif_vb_done_tasklet(&dev->stream[RKCIF_STREAM_MIPI_ID2], dev->rdbk_buf[RDBK_S]);
}
} else {
if (!dev->rdbk_buf[RDBK_L])
@@ -7429,14 +7466,12 @@ static void rkcif_rdbk_frame_end(struct rkcif_stream *stream)
if (!work_busy(&dev->stream[i].tools_vdev->tools_work.work))
schedule_work(&dev->stream[i].tools_vdev->tools_work.work);
else
rkcif_vb_done_oneframe(&dev->stream[i], &dev->rdbk_buf[i]->vb);
rkcif_vb_done_tasklet(&dev->stream[i], dev->rdbk_buf[i]);
spin_unlock_irqrestore(&dev->stream[i].tools_vdev->vbq_lock, flags);
}
} else {
rkcif_vb_done_oneframe(&dev->stream[RKCIF_STREAM_MIPI_ID0],
&dev->rdbk_buf[RDBK_L]->vb);
rkcif_vb_done_oneframe(&dev->stream[RKCIF_STREAM_MIPI_ID1],
&dev->rdbk_buf[RDBK_M]->vb);
rkcif_vb_done_tasklet(&dev->stream[RKCIF_STREAM_MIPI_ID0], dev->rdbk_buf[RDBK_L]);
rkcif_vb_done_tasklet(&dev->stream[RKCIF_STREAM_MIPI_ID1], dev->rdbk_buf[RDBK_M]);
}
} else {
if (!dev->rdbk_buf[RDBK_L])
@@ -7445,8 +7480,6 @@ static void rkcif_rdbk_frame_end(struct rkcif_stream *stream)
v4l2_err(&dev->v4l2_dev, "lost short frames\n");
goto RDBK_FRM_UNMATCH;
}
} else {
rkcif_vb_done_oneframe(stream, &dev->rdbk_buf[RDBK_S]->vb);
}
dev->rdbk_buf[RDBK_L] = NULL;
@@ -7511,10 +7544,10 @@ static void rkcif_buf_done_prepare(struct rkcif_stream *stream,
if (!work_busy(&stream->tools_vdev->tools_work.work))
schedule_work(&stream->tools_vdev->tools_work.work);
else
rkcif_vb_done_oneframe(stream, vb_done);
rkcif_vb_done_tasklet(stream, active_buf);
spin_unlock_irqrestore(&stream->tools_vdev->vbq_lock, flags);
} else {
rkcif_vb_done_oneframe(stream, vb_done);
rkcif_vb_done_tasklet(stream, active_buf);
}
}
} else {
@@ -7528,10 +7561,10 @@ static void rkcif_buf_done_prepare(struct rkcif_stream *stream,
if (!work_busy(&stream->tools_vdev->tools_work.work))
schedule_work(&stream->tools_vdev->tools_work.work);
else
rkcif_vb_done_oneframe(stream, vb_done);
rkcif_vb_done_tasklet(stream, active_buf);
spin_unlock_irqrestore(&stream->tools_vdev->vbq_lock, flags);
} else {
rkcif_vb_done_oneframe(stream, vb_done);
rkcif_vb_done_tasklet(stream, active_buf);
}
}
}
@@ -8485,10 +8518,6 @@ static void rkcif_detect_wake_up_mode_change(struct rkcif_stream *stream)
stream->line_int_cnt = 1;
else if (stream->frame_phase == CIF_CSI_FRAME1_READY)
stream->line_int_cnt = 0;
} else if ((cif_dev->wait_line == 0) && stream->is_line_wake_up) {
stream->is_line_wake_up = false;
}
if (stream->is_line_wake_up) {
rkcif_modify_line_int(stream, true);
if (cif_dev->hdr.hdr_mode == HDR_X2) {
cif_dev->stream[0].is_line_wake_up = true;
@@ -8503,6 +8532,8 @@ static void rkcif_detect_wake_up_mode_change(struct rkcif_stream *stream)
cif_dev->stream[1].line_int_cnt = stream->line_int_cnt;
}
stream->is_line_inten = true;
} else if ((cif_dev->wait_line == 0) && stream->is_line_wake_up) {
stream->is_line_wake_up = false;
}
}
@@ -9018,6 +9049,8 @@ unsigned int rkcif_irq_global(struct rkcif_device *cif_dev)
v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev,
"intstat_glb 0x%x\n",
intstat_glb);
else
return intstat_glb;
if (intstat_glb & SCALE_TOISP_AXI0_ERR) {
v4l2_err(&cif_dev->v4l2_dev,
@@ -9289,8 +9322,10 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev)
int ch_id;
intstat = rkcif_read_register(cif_dev, CIF_REG_DVP_INTSTAT);
rkcif_write_register(cif_dev, CIF_REG_DVP_INTSTAT, intstat);
if (intstat)
rkcif_write_register(cif_dev, CIF_REG_DVP_INTSTAT, intstat);
else
return;
stream = &cif_dev->stream[RKCIF_STREAM_CIF];
@@ -9608,7 +9643,7 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
stream = &cif_dev->stream[RKCIF_STREAM_CIF];
if ((intstat & FRAME_END)) {
struct vb2_v4l2_buffer *vb_done = NULL;
struct rkcif_buffer *active_buf = NULL;
int_en = rkcif_read_register(cif_dev, CIF_REG_DVP_INTEN);
int_en |= LINE_INT_EN;
@@ -9644,11 +9679,11 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
if (cif_frmst & CIF_F0_READY) {
if (stream->curr_buf)
vb_done = &stream->curr_buf->vb;
active_buf = stream->curr_buf;
stream->frame_phase = CIF_CSI_FRAME0_READY;
} else if (cif_frmst & CIF_F1_READY) {
if (stream->next_buf)
vb_done = &stream->next_buf->vb;
active_buf = stream->next_buf;
stream->frame_phase = CIF_CSI_FRAME1_READY;
}
@@ -9662,9 +9697,9 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
ret = rkcif_assign_new_buffer_oneframe(stream,
RKCIF_YUV_ADDR_STATE_UPDATE);
if (vb_done && (!ret)) {
vb_done->sequence = stream->frame_idx;
rkcif_vb_done_oneframe(stream, vb_done);
if (active_buf && (!ret)) {
active_buf->vb.sequence = stream->frame_idx;
rkcif_vb_done_tasklet(stream, active_buf);
}
stream->frame_idx++;
cif_dev->irq_stats.all_frm_end_cnt++;

View File

@@ -513,8 +513,10 @@ struct rkcif_stream {
int buf_num_toisp;
u64 line_int_cnt;
int lack_buf_cnt;
unsigned int buf_wake_up_cnt;
unsigned int buf_wake_up_cnt;
struct rkcif_skip_info skip_info;
struct tasklet_struct vb_done_tasklet;
struct list_head vb_done_list;
int last_rx_buf_idx;
int last_frame_idx;
bool stopping;
@@ -776,7 +778,7 @@ struct rkcif_device {
atomic_t power_cnt;
struct mutex stream_lock; /* lock between streams */
struct mutex scale_lock; /* lock between scale dev */
struct mutex tools_lock; /* lock between tools dev */
struct mutex tools_lock; /* lock between tools dev */
enum rkcif_workmode workmode;
bool can_be_reset;
struct rkmodule_hdr_cfg hdr;