From 1fc0f88577e197771b27161f2941918f0838da5c Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Thu, 13 Apr 2023 21:36:54 +0800 Subject: [PATCH] media: rockchip: vicap: mipi interlaced capture support correct frame sequence correct by frame num witch get from mipi fs/fe short packet, this function need rk356x and later chips to support Signed-off-by: Zefa Chen Change-Id: I62d0dda18dbde45c7a161fdf7a85fd6219c90a31 --- drivers/media/platform/rockchip/cif/capture.c | 409 +++++++++++++++++- drivers/media/platform/rockchip/cif/dev.c | 100 +++++ drivers/media/platform/rockchip/cif/dev.h | 5 + 3 files changed, 502 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 74b2e09cb35e..2e5e72ad880a 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -3525,6 +3525,73 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream, return 0; } +static void rkcif_write_buffer(struct rkcif_stream *stream, struct rkcif_buffer *buffer, + int frame_phase, int even_offset) +{ + struct rkcif_device *dev = stream->cifdev; + struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf; + u32 frm_addr_y, frm_addr_uv; + struct csi_channel_info *channel = &dev->channels[stream->id]; + + if (frame_phase == CIF_CSI_FRAME0_READY) { + frm_addr_y = get_reg_index_of_frm0_y_addr(stream->id); + frm_addr_uv = get_reg_index_of_frm0_uv_addr(stream->id); + } else { + frm_addr_y = get_reg_index_of_frm1_y_addr(stream->id); + frm_addr_uv = get_reg_index_of_frm1_uv_addr(stream->id); + } + if (buffer) { + rkcif_write_register(dev, frm_addr_y, + buffer->buff_addr[RKCIF_PLANE_Y] + even_offset * + (channel->virtual_width / 2)); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, + buffer->buff_addr[RKCIF_PLANE_CBCR] + + even_offset * (channel->virtual_width / 2)); + } else 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); + } +} + +static void rkcif_buf_init_interlace(struct rkcif_stream *stream, int channel_id) +{ + struct rkcif_device *dev = stream->cifdev; + unsigned long flags; + struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf; + int buf_offset = 0; + + spin_lock_irqsave(&stream->vbq_lock, flags); + if (!stream->curr_buf) { + if (!list_empty(&stream->buf_head)) { + stream->curr_buf = list_first_entry(&stream->buf_head, + struct rkcif_buffer, + queue); + list_del(&stream->curr_buf->queue); + } + } + spin_unlock_irqrestore(&stream->vbq_lock, flags); + + if (!stream->odd_frame_first) + buf_offset = 1; + + if (stream->curr_buf) { + rkcif_write_buffer(stream, stream->curr_buf, CIF_CSI_FRAME0_READY, buf_offset); + rkcif_write_buffer(stream, stream->curr_buf, CIF_CSI_FRAME1_READY, buf_offset); + } else { + if (dummy_buf->vaddr) { + rkcif_write_buffer(stream, NULL, CIF_CSI_FRAME0_READY, 0); + rkcif_write_buffer(stream, NULL, CIF_CSI_FRAME1_READY, 0); + } else { + v4l2_err(&dev->v4l2_dev, + "stream[%d] mipi interlace not buf, if cap_en, may cause system death\n", + stream->id); + } + } + +} + static int rkcif_csi_channel_set(struct rkcif_stream *stream, struct csi_channel_info *channel, enum v4l2_mbus_type mbus_type) @@ -3608,7 +3675,11 @@ static int rkcif_csi_channel_set(struct rkcif_stream *stream, channel->crop_st_y << 16 | channel->crop_st_x); /* Set up an buffer for the next frame */ - rkcif_assign_new_buffer_pingpong(stream, + if (dev->chip_id >= CHIP_RK3568_CIF && + stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) + rkcif_buf_init_interlace(stream, channel->id); + else + rkcif_assign_new_buffer_pingpong(stream, RKCIF_YUV_ADDR_STATE_INIT, channel->id); @@ -3926,19 +3997,24 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, rkcif_write_register(dev, get_reg_index_of_id_crop_start(channel->id), channel->crop_st_y << 16 | channel->crop_st_x); - if (mode == RKCIF_STREAM_MODE_CAPTURE) - rkcif_assign_new_buffer_pingpong(stream, - RKCIF_YUV_ADDR_STATE_INIT, - channel->id); - else if (mode == RKCIF_STREAM_MODE_TOISP || - mode == RKCIF_STREAM_MODE_TOISP_RDBK) + if (mode == RKCIF_STREAM_MODE_CAPTURE) { + if (dev->chip_id >= CHIP_RK3568_CIF && + stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) + rkcif_buf_init_interlace(stream, channel->id); + else + rkcif_assign_new_buffer_pingpong(stream, + RKCIF_YUV_ADDR_STATE_INIT, + channel->id); + } else if (mode == RKCIF_STREAM_MODE_TOISP || + mode == RKCIF_STREAM_MODE_TOISP_RDBK) { rkcif_assign_new_buffer_pingpong_toisp(stream, RKCIF_YUV_ADDR_STATE_INIT, channel->id); - else if (mode == RKCIF_STREAM_MODE_ROCKIT) + } else if (mode == RKCIF_STREAM_MODE_ROCKIT) { rkcif_assign_new_buffer_pingpong_rockit(stream, RKCIF_YUV_ADDR_STATE_INIT, channel->id); + } if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && index == (capture_info->multi_dev.dev_num - 1) && @@ -4052,6 +4128,9 @@ static int rkcif_csi_stream_start(struct rkcif_stream *stream, unsigned int mode stream->is_in_vblank = false; stream->is_change_toisp = false; } + stream->interlaced_bad_frame = false; + stream->last_fs_interlaced_phase = 0; + stream->last_fe_interlaced_phase = 0; rkcif_csi_get_vc_num(dev, flags); @@ -8876,6 +8955,69 @@ static void rkcif_buf_done_prepare(struct rkcif_stream *stream, } +static void rkcif_line_wake_up_interlace(struct rkcif_stream *stream, + int mipi_id) +{ + struct rkcif_device *cif_dev = stream->cifdev; + struct rkcif_buffer *active_buf = NULL; + struct rkcif_dummy_buffer *dummy_buf = &cif_dev->hw_dev->dummy_buf; + int frame_id = 0; + int fe_interlaced_phase = 0; + + if (stream->id == 0) + frame_id = rkcif_read_register(cif_dev, CIF_REG_MIPI_FRAME_NUM_VC0); + else if (stream->id == 1) + frame_id = rkcif_read_register(cif_dev, CIF_REG_MIPI_FRAME_NUM_VC1); + else if (stream->id == 2) + frame_id = rkcif_read_register(cif_dev, CIF_REG_MIPI_FRAME_NUM_VC2); + else if (stream->id == 3) + frame_id = rkcif_read_register(cif_dev, CIF_REG_MIPI_FRAME_NUM_VC3); + + if ((frame_id & 0xffff) % 2 == stream->odd_frame_id) { + //odd frame + if (stream->odd_frame_first) + fe_interlaced_phase = CIF_CSI_FRAME0_READY; + else + fe_interlaced_phase = CIF_CSI_FRAME1_READY; + } else { + //even frame + if (stream->odd_frame_first) + fe_interlaced_phase = CIF_CSI_FRAME1_READY; + else + fe_interlaced_phase = CIF_CSI_FRAME0_READY; + } + + v4l2_dbg(rkcif_debug, 3, &cif_dev->v4l2_dev, + "stream[%d] mipi fe interlace phase %d, frame num 0x%x\n", + stream->id, fe_interlaced_phase, frame_id); + + if (fe_interlaced_phase == CIF_CSI_FRAME1_READY && + stream->last_fe_interlaced_phase == CIF_CSI_FRAME0_READY) { + if (dummy_buf->vaddr || stream->next_buf) { + active_buf = stream->curr_buf; + if (active_buf) { + active_buf->vb.vb2_buf.timestamp = stream->readout.fs_timestamp; + active_buf->vb.sequence = (stream->frame_idx - 1) / 2; + if (stream->interlaced_bad_frame) { + stream->interlaced_bad_frame = false; + rkcif_buf_queue(&active_buf->vb.vb2_buf); + v4l2_dbg(rkcif_debug, 3, &cif_dev->v4l2_dev, + "stream[%d] mipi fe interlace bad frame queue, phase %d, line %d\n", + stream->id, fe_interlaced_phase, __LINE__); + } else { + rkcif_vb_done_tasklet(stream, active_buf); + } + stream->curr_buf = stream->next_buf; + stream->next_buf = NULL; + } else { + stream->curr_buf = stream->next_buf; + stream->next_buf = NULL; + } + } + } + stream->last_fe_interlaced_phase = fe_interlaced_phase; +} + static void rkcif_line_wake_up(struct rkcif_stream *stream, int mipi_id) { u32 mode; @@ -9057,6 +9199,82 @@ static void rkcif_deal_readout_time(struct rkcif_stream *stream) spin_unlock_irqrestore(&stream->fps_lock, flags); } +static void rkcif_update_stream_interlace(struct rkcif_device *cif_dev, + struct rkcif_stream *stream, + int mipi_id) +{ + struct rkcif_buffer *active_buf = NULL; + struct rkcif_dummy_buffer *dummy_buf = &cif_dev->hw_dev->dummy_buf; + unsigned long flags; + int frame_id = 0; + int fe_interlaced_phase = 0; + + if (stream->id == 0) + frame_id = rkcif_read_register(cif_dev, CIF_REG_MIPI_FRAME_NUM_VC0); + else if (stream->id == 1) + frame_id = rkcif_read_register(cif_dev, CIF_REG_MIPI_FRAME_NUM_VC1); + else if (stream->id == 2) + frame_id = rkcif_read_register(cif_dev, CIF_REG_MIPI_FRAME_NUM_VC2); + else if (stream->id == 3) + frame_id = rkcif_read_register(cif_dev, CIF_REG_MIPI_FRAME_NUM_VC3); + + if ((frame_id & 0xffff) % 2 == stream->odd_frame_id) { + //odd frame + if (stream->odd_frame_first) + fe_interlaced_phase = CIF_CSI_FRAME0_READY; + else + fe_interlaced_phase = CIF_CSI_FRAME1_READY; + } else { + //even frame + if (stream->odd_frame_first) + fe_interlaced_phase = CIF_CSI_FRAME1_READY; + else + fe_interlaced_phase = CIF_CSI_FRAME0_READY; + } + + v4l2_dbg(rkcif_debug, 3, &cif_dev->v4l2_dev, + "stream[%d] mipi fe interlace phase %d, frame num 0x%x\n", + stream->id, fe_interlaced_phase, frame_id); + + if (!stream->is_line_wake_up) { + spin_lock_irqsave(&stream->fps_lock, flags); + if (stream->frame_phase & CIF_CSI_FRAME0_READY) + stream->fps_stats.frm0_timestamp = ktime_get_ns(); + else if (stream->frame_phase & CIF_CSI_FRAME1_READY) + stream->fps_stats.frm1_timestamp = ktime_get_ns(); + spin_unlock_irqrestore(&stream->fps_lock, flags); + } + + if (!stream->is_line_wake_up) { + if (fe_interlaced_phase == CIF_CSI_FRAME1_READY && + stream->last_fe_interlaced_phase == CIF_CSI_FRAME0_READY) { + if (dummy_buf->vaddr || stream->next_buf) { + active_buf = stream->curr_buf; + if (active_buf) { + active_buf->vb.vb2_buf.timestamp = stream->readout.fs_timestamp; + active_buf->vb.sequence = (stream->frame_idx - 1) / 2; + if (stream->interlaced_bad_frame) { + stream->interlaced_bad_frame = false; + rkcif_buf_queue(&active_buf->vb.vb2_buf); + v4l2_dbg(rkcif_debug, 3, &cif_dev->v4l2_dev, + "stream[%d] mipi fe interlace bad frame queue, phase %d, line %d\n", + stream->id, fe_interlaced_phase, __LINE__); + } else { + rkcif_vb_done_tasklet(stream, active_buf); + } + stream->curr_buf = stream->next_buf; + stream->next_buf = NULL; + } else { + stream->curr_buf = stream->next_buf; + stream->next_buf = NULL; + } + } + } + } + rkcif_deal_readout_time(stream); + stream->last_fe_interlaced_phase = fe_interlaced_phase; +} + static void rkcif_update_stream(struct rkcif_device *cif_dev, struct rkcif_stream *stream, int mipi_id) @@ -10994,6 +11212,151 @@ void rkcif_err_print_work(struct work_struct *work) intstat, lastline); } +static void rkcif_check_mipi_interlaced_frame_id(struct rkcif_stream *stream) +{ + struct rkcif_device *dev = stream->cifdev; + struct rkcif_buffer *buffer = NULL; + struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf; + int frame_id = 0; + int fs_interlaced_phase = 0; + unsigned long flags; + int buf_offset = 0; + + if (stream->id == 0) + frame_id = rkcif_read_register(dev, CIF_REG_MIPI_FRAME_NUM_VC0); + else if (stream->id == 1) + frame_id = rkcif_read_register(dev, CIF_REG_MIPI_FRAME_NUM_VC1); + else if (stream->id == 2) + frame_id = rkcif_read_register(dev, CIF_REG_MIPI_FRAME_NUM_VC2); + else if (stream->id == 3) + frame_id = rkcif_read_register(dev, CIF_REG_MIPI_FRAME_NUM_VC3); + + if ((frame_id & 0xffff) % 2 == stream->odd_frame_id) { + //odd frame + if (stream->odd_frame_first) { + fs_interlaced_phase = CIF_CSI_FRAME0_READY; + buf_offset = 1; + } else { + fs_interlaced_phase = CIF_CSI_FRAME1_READY; + buf_offset = 1; + } + } else { + //even frame + if (stream->odd_frame_first) { + fs_interlaced_phase = CIF_CSI_FRAME1_READY; + buf_offset = 0; + } else { + fs_interlaced_phase = CIF_CSI_FRAME0_READY; + buf_offset = 0; + } + } + + v4l2_dbg(rkcif_debug, 3, &dev->v4l2_dev, + "stream[%d] mipi fs interlace phase %d, frame num 0x%x\n", + stream->id, fs_interlaced_phase, frame_id); + if (stream->last_fs_interlaced_phase == 0) { + buffer = stream->curr_buf; + rkcif_write_buffer(stream, buffer, CIF_CSI_FRAME0_READY, buf_offset); + rkcif_write_buffer(stream, buffer, CIF_CSI_FRAME1_READY, buf_offset); + } else { + if (fs_interlaced_phase == CIF_CSI_FRAME0_READY) { + buffer = stream->curr_buf; + if (stream->last_fs_interlaced_phase == CIF_CSI_FRAME1_READY) { + if (stream->last_fe_interlaced_phase == CIF_CSI_FRAME0_READY) { + if (buffer) + rkcif_buf_queue(&buffer->vb.vb2_buf); + stream->curr_buf = stream->next_buf; + stream->next_buf = NULL; + buffer = stream->curr_buf; + stream->last_fe_interlaced_phase = CIF_CSI_FRAME1_READY; + v4l2_dbg(rkcif_debug, 3, &dev->v4l2_dev, + "stream[%d] mipi fs interlace bad frame queue, phase %d, line %d\n", + stream->id, fs_interlaced_phase, __LINE__); + } + rkcif_write_buffer(stream, buffer, CIF_CSI_FRAME0_READY, buf_offset); + rkcif_write_buffer(stream, buffer, CIF_CSI_FRAME1_READY, buf_offset); + } else if (stream->last_fs_interlaced_phase == CIF_CSI_FRAME0_READY) { + stream->interlaced_bad_frame = true; + rkcif_write_buffer(stream, buffer, CIF_CSI_FRAME0_READY, buf_offset); + rkcif_write_buffer(stream, buffer, CIF_CSI_FRAME1_READY, buf_offset); + v4l2_dbg(rkcif_debug, 3, &dev->v4l2_dev, + "stream[%d] mipi fs interlace bad frame, phase %d, line %d\n", + stream->id, fs_interlaced_phase, __LINE__); + } + } else { + if (stream->last_fs_interlaced_phase == CIF_CSI_FRAME0_READY) { + if (stream->next_buf) { + if (stream->curr_buf) { + rkcif_buf_queue(&stream->curr_buf->vb.vb2_buf); + stream->curr_buf = stream->next_buf; + stream->next_buf = NULL; + } + stream->interlaced_bad_frame = true; + v4l2_dbg(rkcif_debug, 3, &dev->v4l2_dev, + "stream[%d] mipi fs interlace bad frame, phase %d\n", + stream->id, fs_interlaced_phase); + } + spin_lock_irqsave(&stream->vbq_lock, flags); + if (!list_empty(&stream->buf_head)) { + buffer = list_first_entry(&stream->buf_head, + struct rkcif_buffer, queue); + list_del(&buffer->queue); + stream->next_buf = buffer; + } + spin_unlock_irqrestore(&stream->vbq_lock, flags); + if (buffer) { + rkcif_write_buffer(stream, buffer, CIF_CSI_FRAME0_READY, buf_offset); + rkcif_write_buffer(stream, buffer, CIF_CSI_FRAME1_READY, buf_offset); + } else if (dummy_buf->vaddr) { + stream->interlaced_bad_frame = true; + rkcif_write_buffer(stream, NULL, CIF_CSI_FRAME0_READY, buf_offset); + rkcif_write_buffer(stream, NULL, CIF_CSI_FRAME1_READY, buf_offset); + v4l2_dbg(rkcif_debug, 3, &dev->v4l2_dev, + "stream[%d] mipi interlace not buf, use dummy buf, line %d\n", + stream->id, __LINE__); + } else { + v4l2_dbg(rkcif_debug, 3, &dev->v4l2_dev, + "stream[%d] mipi interlace not buf, may overwrite buf, line %d\n", + stream->id, __LINE__); + } + } else { + if (stream->last_fe_interlaced_phase != CIF_CSI_FRAME1_READY) { + buffer = stream->curr_buf; + if (buffer) + rkcif_buf_queue(&buffer->vb.vb2_buf); + stream->curr_buf = stream->next_buf; + stream->next_buf = NULL; + stream->last_fe_interlaced_phase = CIF_CSI_FRAME1_READY; + v4l2_dbg(rkcif_debug, 3, &dev->v4l2_dev, + "stream[%d] mipi fs interlace bad frame queue, phase %d, line %d\n", + stream->id, fs_interlaced_phase, __LINE__); + } + if (stream->next_buf) { + buffer = stream->next_buf; + rkcif_write_buffer(stream, buffer, CIF_CSI_FRAME0_READY, buf_offset); + rkcif_write_buffer(stream, buffer, CIF_CSI_FRAME1_READY, buf_offset); + } else if (stream->curr_buf) { + buffer = stream->curr_buf; + rkcif_write_buffer(stream, buffer, CIF_CSI_FRAME0_READY, buf_offset); + rkcif_write_buffer(stream, buffer, CIF_CSI_FRAME1_READY, buf_offset); + } else if (dummy_buf->vaddr) { + rkcif_write_buffer(stream, NULL, CIF_CSI_FRAME0_READY, buf_offset); + rkcif_write_buffer(stream, NULL, CIF_CSI_FRAME1_READY, buf_offset); + stream->interlaced_bad_frame = true; + v4l2_dbg(rkcif_debug, 3, &dev->v4l2_dev, + "stream[%d] mipi interlace not buf, use dummy buf, line %d\n", + stream->id, __LINE__); + } else { + v4l2_dbg(rkcif_debug, 3, &dev->v4l2_dev, + "stream[%d] mipi interlace not buf, may overwrite buf, line %d\n", + stream->id, __LINE__); + } + } + } + } + stream->last_fs_interlaced_phase = fs_interlaced_phase; +} + /* pingpong irq for rk3588 and next */ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) { @@ -11141,8 +11504,13 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) v4l2_dbg(4, rkcif_debug, &cif_dev->v4l2_dev, "dma capture by vicap, is_updata %d, group mode %d, dma_en %d\n", is_update, cif_dev->sync_cfg.type, stream->dma_en); - if (is_update) - rkcif_update_stream(cif_dev, stream, mipi_id); + if (is_update) { + if (cif_dev->chip_id >= CHIP_RK3568_CIF && + stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) + rkcif_update_stream_interlace(cif_dev, stream, mipi_id); + else + rkcif_update_stream(cif_dev, stream, mipi_id); + } } else if (stream->dma_en & RKCIF_DMAEN_BY_ISP) { v4l2_dbg(4, rkcif_debug, &cif_dev->v4l2_dev, "dma capture by isp, dma_en 0x%x\n", @@ -11246,6 +11614,9 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) if (stream->to_en_dma) rkcif_enable_dma_capture(stream, false); spin_unlock_irqrestore(&stream->vbq_lock, flags); + if (cif_dev->chip_id >= CHIP_RK3568_CIF && + stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) + rkcif_check_mipi_interlaced_frame_id(stream); } if (intstat & CSI_LINE_INTSTAT_V1(i)) { stream = &cif_dev->stream[i]; @@ -11259,6 +11630,9 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) if (cif_dev->sditf[0] && (cif_dev->sditf[0]->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO || cif_dev->sditf[0]->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO_ONE_FRAME)) rkcif_line_wake_up_rdbk(stream, stream->id); + else if (cif_dev->chip_id >= CHIP_RK3568_CIF && + stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) + rkcif_line_wake_up_interlace(stream, stream->id); else rkcif_line_wake_up(stream, stream->id); rkcif_modify_line_int(stream, false); @@ -11461,7 +11835,11 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev) if (stream->crop_dyn_en) rkcif_dynamic_crop(stream); - rkcif_update_stream(cif_dev, stream, mipi_id); + if (cif_dev->chip_id >= CHIP_RK3568_CIF && + stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) + rkcif_update_stream_interlace(cif_dev, stream, mipi_id); + else + rkcif_update_stream(cif_dev, stream, mipi_id); rkcif_detect_wake_up_mode_change(stream); rkcif_monitor_reset_event(cif_dev); if (mipi_id == RKCIF_STREAM_MIPI_ID0) { @@ -11489,12 +11867,19 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev) spin_unlock_irqrestore(&stream->fps_lock, flags); } stream->is_in_vblank = false; + if (cif_dev->chip_id >= CHIP_RK3568_CIF && + stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) + rkcif_check_mipi_interlaced_frame_id(stream); } if (intstat & CSI_LINE_INTSTAT(i)) { stream = &cif_dev->stream[i]; if (stream->is_line_inten) { stream->line_int_cnt++; - rkcif_line_wake_up(stream, stream->id); + if (cif_dev->chip_id >= CHIP_RK3568_CIF && + stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) + rkcif_line_wake_up_interlace(stream, stream->id); + else + rkcif_line_wake_up(stream, stream->id); rkcif_modify_line_int(stream, false); stream->is_line_inten = false; } diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index c6988c76e38a..d5fe2010c6b4 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -599,6 +599,104 @@ static ssize_t rkcif_store_rdbk_debug(struct device *dev, } static DEVICE_ATTR(rdbk_debug, 0200, rkcif_show_rdbk_debug, rkcif_store_rdbk_debug); +static ssize_t rkcif_show_odd_frame_id(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 %d %d %d\n", + cif_dev->stream[0].odd_frame_id ? 1 : 0, + cif_dev->stream[1].odd_frame_id ? 1 : 0, + cif_dev->stream[2].odd_frame_id ? 1 : 0, + cif_dev->stream[3].odd_frame_id ? 1 : 0); + return ret; +} + +static ssize_t rkcif_store_odd_frame_id(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 i, index; + char val[4]; + + if (buf) { + index = 0; + for (i = 0; i < len; i++) { + if (buf[i] == ' ') + continue; + else if (buf[i] == '\0') + break; + val[index] = buf[i]; + index++; + if (index == 4) + break; + } + + for (i = 0; i < index; i++) { + if (val[i] - '0' == 0) + cif_dev->stream[i].odd_frame_id = 0; + else + cif_dev->stream[i].odd_frame_id = 1; + } + } + + return len; +} +static DEVICE_ATTR(odd_frame_id, S_IWUSR | S_IRUSR, + rkcif_show_odd_frame_id, rkcif_store_odd_frame_id); + +static ssize_t rkcif_show_odd_frame_fisrt(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 %d %d %d\n", + cif_dev->stream[0].odd_frame_first ? 1 : 0, + cif_dev->stream[1].odd_frame_first ? 1 : 0, + cif_dev->stream[2].odd_frame_first ? 1 : 0, + cif_dev->stream[3].odd_frame_first ? 1 : 0); + return ret; +} + +static ssize_t rkcif_store_odd_frame_fisrt(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 i, index; + char val[4]; + + if (buf) { + index = 0; + for (i = 0; i < len; i++) { + if (buf[i] == ' ') + continue; + else if (buf[i] == '\0') + break; + val[index] = buf[i]; + index++; + if (index == 4) + break; + } + + for (i = 0; i < index; i++) { + if (val[i] - '0' == 0) + cif_dev->stream[i].odd_frame_first = 0; + else + cif_dev->stream[i].odd_frame_first = 1; + } + } + + return len; +} +static DEVICE_ATTR(odd_frame_first, S_IWUSR | S_IRUSR, + rkcif_show_odd_frame_fisrt, rkcif_store_odd_frame_fisrt); + static struct attribute *dev_attrs[] = { &dev_attr_compact_test.attr, &dev_attr_wait_line.attr, @@ -610,6 +708,8 @@ static struct attribute *dev_attrs[] = { &dev_attr_scale_ch3_blc.attr, &dev_attr_fps.attr, &dev_attr_rdbk_debug.attr, + &dev_attr_odd_frame_id.attr, + &dev_attr_odd_frame_first.attr, NULL, }; diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index 912e41abb48a..56df9877b985 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -512,6 +512,10 @@ struct rkcif_stream { unsigned int frame_idx; int frame_phase; int frame_phase_cache; + int last_fs_interlaced_phase; + int last_fe_interlaced_phase; + int odd_frame_id; + int odd_frame_first; unsigned int crop_mask; /* lock between irq and buf_queue */ struct list_head buf_head; @@ -583,6 +587,7 @@ struct rkcif_stream { bool is_wait_dma_stop; bool is_single_cap; bool is_wait_stop_complete; + bool interlaced_bad_frame; }; struct rkcif_lvds_subdev {