From 95bfb5ca3aee800ddbac8842e6169ed6962a6b37 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Thu, 12 Aug 2021 19:51:17 +0800 Subject: [PATCH] media: rockchip: cif supports dummy buffer configurable Signed-off-by: Zefa Chen Change-Id: Icc62c1324affd65934872dfb7c1d29f15e28bb3b --- drivers/media/platform/rockchip/cif/Kconfig | 14 ++ drivers/media/platform/rockchip/cif/capture.c | 126 ++++++++++++++++-- drivers/media/platform/rockchip/cif/dev.c | 50 ++++++- drivers/media/platform/rockchip/cif/dev.h | 1 + drivers/media/platform/rockchip/cif/procfs.c | 22 +-- 5 files changed, 186 insertions(+), 27 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/Kconfig b/drivers/media/platform/rockchip/cif/Kconfig index 7ae825d4dcf5..592842bf3386 100644 --- a/drivers/media/platform/rockchip/cif/Kconfig +++ b/drivers/media/platform/rockchip/cif/Kconfig @@ -24,3 +24,17 @@ config ROCKCHIP_CIF_WORKMODE_ONEFRAME bool "interface works in oneframe mode" endchoice + +choice + prompt "rockchip rkcif device dummy buffer choice" + depends on VIDEO_ROCKCHIP_CIF + default ROCKCHIP_CIF_USE_DUMMY_BUF + +config ROCKCHIP_CIF_USE_DUMMY_BUF + bool "rkcif use dummy buffer" + +config ROCKCHIP_CIF_USE_NONE_DUMMY_BUF + bool "rkcif not use dummy buffer" + +endchoice + diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 77eda1fcb7fb..87475ebd99f4 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -1162,6 +1162,7 @@ static int rkcif_assign_new_buffer_oneframe(struct rkcif_stream *stream, enum rkcif_yuvaddr_state stat) { struct rkcif_device *dev = stream->cifdev; + struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf; struct rkcif_buffer *buffer = NULL; u32 frm_addr_y = CIF_REG_DVP_FRM0_ADDR_Y; u32 frm_addr_uv = CIF_REG_DVP_FRM0_ADDR_UV; @@ -1184,6 +1185,13 @@ static int rkcif_assign_new_buffer_oneframe(struct rkcif_stream *stream, stream->curr_buf->buff_addr[RKCIF_PLANE_Y]); rkcif_write_register(dev, CIF_REG_DVP_FRM0_ADDR_UV, stream->curr_buf->buff_addr[RKCIF_PLANE_CBCR]); + } else { + if (dummy_buf->vaddr) { + rkcif_write_register(dev, CIF_REG_DVP_FRM0_ADDR_Y, + dummy_buf->dma_addr); + rkcif_write_register(dev, CIF_REG_DVP_FRM0_ADDR_UV, + dummy_buf->dma_addr); + } } if (!stream->next_buf) { @@ -1199,6 +1207,13 @@ static int rkcif_assign_new_buffer_oneframe(struct rkcif_stream *stream, stream->next_buf->buff_addr[RKCIF_PLANE_Y]); rkcif_write_register(dev, CIF_REG_DVP_FRM1_ADDR_UV, stream->next_buf->buff_addr[RKCIF_PLANE_CBCR]); + } else { + if (dummy_buf->vaddr) { + rkcif_write_register(dev, CIF_REG_DVP_FRM1_ADDR_Y, + dummy_buf->dma_addr); + rkcif_write_register(dev, CIF_REG_DVP_FRM1_ADDR_UV, + dummy_buf->dma_addr); + } } } else if (stat == RKCIF_YUV_ADDR_STATE_UPDATE) { if (!list_empty(&stream->buf_head)) { @@ -1214,6 +1229,10 @@ static int rkcif_assign_new_buffer_oneframe(struct rkcif_stream *stream, buffer = stream->next_buf; } } else { + if (dummy_buf->vaddr && stream->frame_phase == CIF_CSI_FRAME0_READY) + stream->curr_buf = NULL; + if (dummy_buf->vaddr && stream->frame_phase == CIF_CSI_FRAME1_READY) + stream->next_buf = NULL; buffer = NULL; } if (stream->frame_phase == CIF_CSI_FRAME0_READY) { @@ -1230,7 +1249,14 @@ static int rkcif_assign_new_buffer_oneframe(struct rkcif_stream *stream, rkcif_write_register(dev, frm_addr_uv, buffer->buff_addr[RKCIF_PLANE_CBCR]); } else { - ret = -EINVAL; + if (dummy_buf->vaddr) { + rkcif_write_register(dev, frm_addr_y, + dummy_buf->dma_addr); + rkcif_write_register(dev, frm_addr_uv, + dummy_buf->dma_addr); + } else { + ret = -EINVAL; + } v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "not active buffer, frame Drop\n"); } @@ -1280,6 +1306,12 @@ static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream, if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) rkcif_write_register(dev, frm0_addr_uv, stream->curr_buf->buff_addr[RKCIF_PLANE_CBCR]); + } else { + if (dummy_buf->vaddr) { + rkcif_write_register(dev, frm0_addr_y, dummy_buf->dma_addr); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm0_addr_uv, dummy_buf->dma_addr); + } } if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) { @@ -1306,6 +1338,12 @@ static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream, if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) rkcif_write_register(dev, frm1_addr_uv, stream->next_buf->buff_addr[RKCIF_PLANE_CBCR]); + } else { + if (dummy_buf->vaddr) { + rkcif_write_register(dev, frm1_addr_y, dummy_buf->dma_addr); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm1_addr_uv, dummy_buf->dma_addr); + } } } spin_unlock_irqrestore(&stream->vbq_lock, flags); @@ -1344,6 +1382,7 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, int channel_id) { struct rkcif_device *dev = stream->cifdev; + struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf; struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; struct rkcif_buffer *buffer = NULL; u32 frm_addr_y, frm_addr_uv; @@ -1370,6 +1409,10 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, spin_lock_irqsave(&stream->vbq_lock, flags); if (!list_empty(&stream->buf_head)) { + if (!dummy_buf->vaddr && + stream->curr_buf == stream->next_buf && + stream->cif_fmt_in->field != V4L2_FIELD_INTERLACED) + ret = -EINVAL; if (stream->frame_phase == CIF_CSI_FRAME0_READY) { stream->curr_buf = list_first_entry(&stream->buf_head, struct rkcif_buffer, queue); @@ -1393,6 +1436,22 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, } } else { buffer = NULL; + if (dummy_buf->vaddr) { + if (stream->frame_phase == CIF_CSI_FRAME0_READY) + stream->curr_buf = NULL; + else if (stream->frame_phase == CIF_CSI_FRAME1_READY) + stream->next_buf = NULL; + } else if (stream->curr_buf != stream->next_buf) { + if (stream->frame_phase == CIF_CSI_FRAME0_READY) { + stream->curr_buf = stream->next_buf; + buffer = stream->next_buf; + } else if (stream->frame_phase == CIF_CSI_FRAME1_READY) { + stream->next_buf = stream->curr_buf; + buffer = stream->curr_buf; + } + + } + } spin_unlock_irqrestore(&stream->vbq_lock, flags); @@ -1412,7 +1471,13 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, buffer->buff_addr[RKCIF_PLANE_CBCR]); } } else { - ret = -EINVAL; + if (dummy_buf->vaddr) { + rkcif_write_register(dev, frm_addr_y, dummy_buf->dma_addr); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, dummy_buf->dma_addr); + } else { + ret = -EINVAL; + } v4l2_info(&dev->v4l2_dev, "not active buffer, skip current frame, %s stream[%d]\n", (mbus_cfg->type == V4L2_MBUS_CSI2 || @@ -1424,11 +1489,16 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, static int rkcif_get_new_buffer_wake_up_mode(struct rkcif_stream *stream) { + struct rkcif_device *dev = stream->cifdev; + struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf; int ret = 0; unsigned long flags; spin_lock_irqsave(&stream->vbq_lock, flags); if (!list_empty(&stream->buf_head)) { + if (!dummy_buf->vaddr && + stream->curr_buf == stream->next_buf) + ret = -EINVAL; if (stream->line_int_cnt % 2) { stream->curr_buf = list_first_entry(&stream->buf_head, struct rkcif_buffer, queue); @@ -1442,8 +1512,21 @@ static int rkcif_get_new_buffer_wake_up_mode(struct rkcif_stream *stream) } stream->is_buf_active = true; } else { - ret = -EINVAL; stream->is_buf_active = false; + if (dummy_buf->vaddr) { + if (stream->line_int_cnt % 2) + stream->curr_buf = NULL; + else + stream->next_buf = NULL; + } else if (stream->curr_buf != stream->next_buf) { + if (stream->line_int_cnt % 2) + stream->curr_buf = stream->next_buf; + else + stream->next_buf = stream->curr_buf; + stream->is_buf_active = true; + } else { + ret = -EINVAL; + } } spin_unlock_irqrestore(&stream->vbq_lock, flags); @@ -1453,6 +1536,7 @@ static int rkcif_get_new_buffer_wake_up_mode(struct rkcif_stream *stream) static int rkcif_update_new_buffer_wake_up_mode(struct rkcif_stream *stream) { struct rkcif_device *dev = stream->cifdev; + struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf; struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; struct rkcif_buffer *buffer = NULL; u32 frm_addr_y, frm_addr_uv; @@ -1490,7 +1574,13 @@ static int rkcif_update_new_buffer_wake_up_mode(struct rkcif_stream *stream) rkcif_write_register(dev, frm_addr_uv, buffer->buff_addr[RKCIF_PLANE_CBCR]); } else { - ret = -EINVAL; + if (dummy_buf->vaddr) { + rkcif_write_register(dev, frm_addr_y, dummy_buf->dma_addr); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, dummy_buf->dma_addr); + } else { + ret = -EINVAL; + } v4l2_info(&dev->v4l2_dev, "not active buffer, skip current frame, %s stream[%d]\n", (mbus_cfg->type == V4L2_MBUS_CSI2 || @@ -2894,8 +2984,8 @@ static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count) if (ret < 0) goto destroy_buf; - if (dev->active_sensor && - dev->active_sensor->mbus.type == V4L2_MBUS_BT656 && + if (((dev->active_sensor && dev->active_sensor->mbus.type == V4L2_MBUS_BT656) || + dev->is_use_dummybuf) && (!dev->dummy_buf.vaddr)) { ret = rkcif_create_dummy_buf(stream); if (ret < 0) { @@ -3034,7 +3124,10 @@ static int rkcif_init_vb2_queue(struct vb2_queue *q, else q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct rkcif_buffer); - q->min_buffers_needed = CIF_REQ_BUFS_MIN; + if (stream->cifdev->is_use_dummybuf) + q->min_buffers_needed = 1; + else + q->min_buffers_needed = CIF_REQ_BUFS_MIN; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->lock = &stream->vnode.vlock; q->dev = hw_dev->dev; @@ -4920,7 +5013,8 @@ static void rkcif_buf_done_prepare(struct rkcif_stream *stream, cif_dev->rdbk_buf[RDBK_L]->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; rkcif_buf_queue(&cif_dev->rdbk_buf[RDBK_L]->vb.vb2_buf); } - cif_dev->rdbk_buf[RDBK_L] = active_buf; + if (active_buf) + cif_dev->rdbk_buf[RDBK_L] = active_buf; } else if (mipi_id == RKCIF_STREAM_MIPI_ID1) { if (cif_dev->rdbk_buf[RDBK_M]) { v4l2_err(&cif_dev->v4l2_dev, @@ -4931,8 +5025,8 @@ static void rkcif_buf_done_prepare(struct rkcif_stream *stream, cif_dev->rdbk_buf[RDBK_M]->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; rkcif_buf_queue(&cif_dev->rdbk_buf[RDBK_M]->vb.vb2_buf); } - - cif_dev->rdbk_buf[RDBK_M] = active_buf; + if (active_buf) + cif_dev->rdbk_buf[RDBK_M] = active_buf; if (cif_dev->hdr.mode == HDR_X2) rkcif_rdbk_frame_end(stream); } else if (mipi_id == RKCIF_STREAM_MIPI_ID2) { @@ -4945,7 +5039,8 @@ static void rkcif_buf_done_prepare(struct rkcif_stream *stream, cif_dev->rdbk_buf[RDBK_S]->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; rkcif_buf_queue(&cif_dev->rdbk_buf[RDBK_S]->vb.vb2_buf); } - cif_dev->rdbk_buf[RDBK_S] = active_buf; + if (active_buf) + cif_dev->rdbk_buf[RDBK_S] = active_buf; if (cif_dev->hdr.mode == HDR_X3) rkcif_rdbk_frame_end(stream); } @@ -5016,10 +5111,12 @@ static void rkcif_deal_readout_time(struct rkcif_stream *stream) } else if ((cif_dev->hdr.mode == HDR_X2) && (stream->id == RKCIF_STREAM_MIPI_ID1)) { detect_stream->readout.early_time = stream->readout.fe_timestamp - stream->readout.wk_timestamp; - detect_stream->readout.total_time = stream->readout.fe_timestamp - detect_stream->readout.fs_timestamp; + detect_stream->readout.total_time = stream->readout.fe_timestamp - detect_stream->readout.fe_timestamp; + detect_stream->readout.total_time += detect_stream->readout.readout_time; } else if ((cif_dev->hdr.mode == HDR_X3) && (stream->id == RKCIF_STREAM_MIPI_ID2)) { detect_stream->readout.early_time = stream->readout.fe_timestamp - stream->readout.wk_timestamp; - detect_stream->readout.total_time = stream->readout.fe_timestamp - detect_stream->readout.fs_timestamp; + detect_stream->readout.total_time = stream->readout.fe_timestamp - detect_stream->readout.fe_timestamp; + detect_stream->readout.total_time += detect_stream->readout.readout_time; } if (!stream->is_line_wake_up) detect_stream->readout.early_time = 0; @@ -5059,7 +5156,8 @@ static void rkcif_update_stream(struct rkcif_device *cif_dev, cif_dev->buf_wake_up_cnt += 1; } - rkcif_deal_readout_time(stream); + if (cif_dev->inf_id == RKCIF_MIPI_LVDS) + rkcif_deal_readout_time(stream); if (!stream->is_line_wake_up) { ret = rkcif_assign_new_buffer_pingpong(stream, diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index 5fe6aec953af..445a3ca864e7 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -120,15 +120,52 @@ static ssize_t rkcif_store_line_int_num(struct device *dev, return len; } +static ssize_t rkcif_show_dummybuf_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev); + int ret; + + ret = snprintf(buf, PAGE_SIZE, "%d\n", + cif_dev->is_use_dummybuf); + return ret; +} + +static ssize_t rkcif_store_dummybuf_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev); + int val = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &val); + if (!ret) { + if (val) + cif_dev->is_use_dummybuf = true; + else + cif_dev->is_use_dummybuf = false; + } else { + dev_info(cif_dev->dev, "set dummy buf mode failed\n"); + } + return len; +} + static DEVICE_ATTR(compact_test, S_IWUSR | S_IRUSR, rkcif_show_compact_mode, rkcif_store_compact_mode); static DEVICE_ATTR(wait_line, S_IWUSR | S_IRUSR, rkcif_show_line_int_num, rkcif_store_line_int_num); +static DEVICE_ATTR(is_use_dummybuf, S_IWUSR | S_IRUSR, + rkcif_show_dummybuf_mode, rkcif_store_dummybuf_mode); + + static struct attribute *dev_attrs[] = { &dev_attr_compact_test.attr, &dev_attr_wait_line.attr, + &dev_attr_is_use_dummybuf.attr, NULL, }; @@ -1096,6 +1133,12 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int cif_dev->workmode = RKCIF_WORKMODE_PINGPONG; #endif +#if defined(CONFIG_ROCKCHIP_CIF_USE_DUMMY_BUF) + cif_dev->is_use_dummybuf = true; +#else + cif_dev->is_use_dummybuf = false; +#endif + strlcpy(cif_dev->media_dev.model, dev_name(dev), sizeof(cif_dev->media_dev.model)); cif_dev->media_dev.dev = dev; @@ -1226,9 +1269,6 @@ static int rkcif_plat_probe(struct platform_device *pdev) dev_set_drvdata(dev, cif_dev); cif_dev->dev = dev; - if (sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp)) - return -ENODEV; - rkcif_attach_hw(cif_dev); rkcif_parse_dts(cif_dev); @@ -1239,6 +1279,9 @@ static int rkcif_plat_probe(struct platform_device *pdev) return ret; } + if (sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp)) + return -ENODEV; + if (rkcif_proc_init(cif_dev)) dev_warn(dev, "dev:%s create proc failed\n", dev_name(dev)); @@ -1257,6 +1300,7 @@ static int rkcif_plat_remove(struct platform_device *pdev) rkcif_detach_hw(cif_dev); rkcif_proc_cleanup(cif_dev); rkcif_csi2_unregister_notifier(&cif_dev->reset_notifier); + sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp); del_timer_sync(&cif_dev->reset_watchdog_timer.timer); return 0; diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index 333852216fdc..812432f1cc2f 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -551,6 +551,7 @@ struct rkcif_device { bool is_start_hdr; bool reset_work_cancel; bool iommu_en; + bool is_use_dummybuf; }; extern struct platform_driver rkcif_plat_drv; diff --git a/drivers/media/platform/rockchip/cif/procfs.c b/drivers/media/platform/rockchip/cif/procfs.c index e77b2c8fe6ac..0895f06a71a1 100644 --- a/drivers/media/platform/rockchip/cif/procfs.c +++ b/drivers/media/platform/rockchip/cif/procfs.c @@ -315,17 +315,19 @@ static void rkcif_show_format(struct rkcif_device *dev, struct seq_file *f) dev->channels[0].crop_st_x, dev->channels[0].crop_st_y); seq_printf(f, "\tcompact:%s\n", stream->is_compact ? "enable" : "disabled"); seq_printf(f, "\tframe amount:%d\n", stream->frame_idx); - time_val = div_u64(stream->readout.early_time, 1000000); - seq_printf(f, "\tearly:%u ms\n", time_val); - if (dev->hdr.mode == NO_HDR) { - time_val = div_u64(stream->readout.readout_time, 1000000); - seq_printf(f, "\treadout:%u ms\n", time_val); - } else { - time_val = div_u64(stream->readout.readout_time, 1000000); - seq_printf(f, "\tsingle readout:%u ms\n", time_val); - time_val = div_u64(stream->readout.total_time, 1000000); - seq_printf(f, "\ttotal readout:%u ms\n", time_val); + if (dev->inf_id == RKCIF_MIPI_LVDS) { + time_val = div_u64(stream->readout.early_time, 1000000); + seq_printf(f, "\tearly:%u ms\n", time_val); + if (dev->hdr.mode == NO_HDR) { + time_val = div_u64(stream->readout.readout_time, 1000000); + seq_printf(f, "\treadout:%u ms\n", time_val); + } else { + time_val = div_u64(stream->readout.readout_time, 1000000); + seq_printf(f, "\tsingle readout:%u ms\n", time_val); + time_val = div_u64(stream->readout.total_time, 1000000); + seq_printf(f, "\ttotal readout:%u ms\n", time_val); + } } seq_printf(f, "\trate:%llu ms\n", fps); fps = div_u64(1000, fps);