diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 4baa5d2ed896..bd977c7dbe5c 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -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++; diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index bd46a1554af5..8f7d18135b0f 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -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;