Merge commit 'f4895714f4a155afc89647e4852c5c69c40b8e34'

* commit 'f4895714f4a155afc89647e4852c5c69c40b8e34':
  arm64: dts: rockchip: rk3588-evb7-v11-imx415: remove cam_ircut0
  mtd: spinand: skyhigh: Fix devices information
  media: rockchip: vicap distinguish different interlace mode
  media: rockchip: vicap: mipi interlaced capture support correct frame sequence

Change-Id: Ia3afc2dc80006c56a825101d89bec09221e17483
This commit is contained in:
Tao Huang
2024-02-04 11:42:24 +08:00
5 changed files with 564 additions and 60 deletions

View File

@@ -5,14 +5,6 @@
*/
/ {
cam_ircut0: cam_ircut {
status = "okay";
compatible = "rockchip,ircut";
ircut-open-gpios = <&gpio4 RK_PA0 GPIO_ACTIVE_HIGH>;
ircut-close-gpios = <&gpio4 RK_PA1 GPIO_ACTIVE_HIGH>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
};
vcc_mipidphy0: vcc-mipidcphy0-regulator {
compatible = "regulator-fixed";
gpio = <&gpio1 RK_PB2 GPIO_ACTIVE_HIGH>;
@@ -74,7 +66,6 @@
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "CMK-OT2022-PX1";
rockchip,camera-module-lens-name = "IR0147-50IRC-8M-F20";
lens-focus = <&cam_ircut0>;
port {
imx415_out0: endpoint {
remote-endpoint = <&mipidphy0_in_ucam0>;

View File

@@ -555,6 +555,19 @@ static const struct cif_input_fmt in_fmts[] = {
}
};
static inline int rkcif_get_interlace_mode(struct rkcif_stream *stream)
{
if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
if (stream->cifdev->use_hw_interlace)
return RKCIF_INTERLACE_HW;
else if (stream->cifdev->chip_id >= CHIP_RK3568_CIF)
return RKCIF_INTERLACE_SOFT_AUTO;
else
return RKCIF_INTERLACE_SOFT;
}
return RKCIF_INTERLACE_NONE;
}
static int rkcif_output_fmt_check(struct rkcif_stream *stream,
const struct cif_output_fmt *output_fmt)
{
@@ -2411,7 +2424,7 @@ static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream,
}
}
if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
if (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT) {
stream->next_buf = stream->curr_buf;
if (stream->next_buf) {
buff_addr_y = stream->next_buf->buff_addr[RKCIF_PLANE_Y];
@@ -2557,7 +2570,7 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream,
if (!dummy_buf->vaddr &&
stream->curr_buf == stream->next_buf &&
stream->cif_fmt_in->field != V4L2_FIELD_INTERLACED)
rkcif_get_interlace_mode(stream) != RKCIF_INTERLACE_SOFT)
ret = -EINVAL;
if (stream->frame_phase == CIF_CSI_FRAME0_READY) {
@@ -2575,7 +2588,7 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream,
} else if (stream->frame_phase == CIF_CSI_FRAME1_READY) {
if (!stream->next_buf)
ret = -EINVAL;
if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
if (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT) {
if (stream->next_buf != stream->curr_buf) {
stream->next_buf = stream->curr_buf;
buffer = stream->next_buf;
@@ -2601,7 +2614,7 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream,
if (stream->frame_phase == CIF_CSI_FRAME0_READY) {
stream->curr_buf = NULL;
} else if (stream->frame_phase == CIF_CSI_FRAME1_READY) {
if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
if (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT) {
stream->next_buf = stream->curr_buf;
buffer = stream->next_buf;
} else {
@@ -2630,7 +2643,7 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream,
if (buffer) {
buff_addr_y = buffer->buff_addr[RKCIF_PLANE_Y];
buff_addr_cbcr = buffer->buff_addr[RKCIF_PLANE_CBCR];
if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED &&
if (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT &&
stream->frame_phase == CIF_CSI_FRAME1_READY) {
if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) {
rkcif_write_buff_addr_multi_dev_combine(stream,
@@ -3042,7 +3055,8 @@ static void rkcif_assign_new_buffer_init_rockit(struct rkcif_stream *stream,
}
}
if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
if (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT ||
rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO) {
stream->next_buf_rockit = stream->curr_buf_rockit;
if (stream->next_buf_rockit) {
rkcif_write_register(dev, frm1_addr_y,
@@ -3152,7 +3166,8 @@ static int rkcif_assign_new_buffer_update_rockit(struct rkcif_stream *stream,
if (!dummy_buf->vaddr &&
stream->curr_buf_rockit == stream->next_buf_rockit &&
stream->cif_fmt_in->field != V4L2_FIELD_INTERLACED)
(rkcif_get_interlace_mode(stream) != RKCIF_INTERLACE_SOFT ||
rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO))
ret = -EINVAL;
if (stream->frame_phase == CIF_CSI_FRAME0_READY) {
@@ -3167,7 +3182,8 @@ static int rkcif_assign_new_buffer_update_rockit(struct rkcif_stream *stream,
} else if (stream->frame_phase == CIF_CSI_FRAME1_READY) {
if (!stream->next_buf_rockit)
ret = -EINVAL;
if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
if (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT ||
rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO) {
if (stream->next_buf_rockit != stream->curr_buf_rockit) {
stream->next_buf_rockit = stream->curr_buf_rockit;
buffer = stream->next_buf_rockit;
@@ -3190,7 +3206,8 @@ static int rkcif_assign_new_buffer_update_rockit(struct rkcif_stream *stream,
if (stream->frame_phase == CIF_CSI_FRAME0_READY) {
stream->curr_buf_rockit = NULL;
} else if (stream->frame_phase == CIF_CSI_FRAME1_READY) {
if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
if (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT ||
rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO) {
stream->next_buf_rockit = stream->curr_buf_rockit;
buffer = stream->next_buf_rockit;
} else {
@@ -3216,7 +3233,8 @@ static int rkcif_assign_new_buffer_update_rockit(struct rkcif_stream *stream,
stream->frame_phase_cache = stream->frame_phase;
if (buffer) {
if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED &&
if ((rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT ||
rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO) &&
stream->frame_phase == CIF_CSI_FRAME1_READY) {
rkcif_write_register(dev, frm_addr_y,
buffer->buff_addr[RKCIF_PLANE_Y] + (channel->virtual_width / 2));
@@ -3441,7 +3459,8 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream,
if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE)
channel->left_virtual_width *= 2;
}
if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
if (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT ||
rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO) {
channel->virtual_width *= 2;
channel->height /= 2;
}
@@ -3474,6 +3493,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)
@@ -3557,7 +3643,10 @@ 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 (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO)
rkcif_buf_init_interlace(stream, channel->id);
else
rkcif_assign_new_buffer_pingpong(stream,
RKCIF_YUV_ADDR_STATE_INIT,
channel->id);
@@ -3875,19 +3964,23 @@ 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 (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO)
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) &&
@@ -4000,6 +4093,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;
channel = &dev->channels[stream->id];
channel->id = stream->id;
@@ -4235,7 +4331,6 @@ static void rkcif_check_buffer_update_pingpong(struct rkcif_stream *stream,
struct rkcif_device *dev = stream->cifdev;
struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus;
struct rkcif_buffer *buffer = NULL;
struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf;
u32 frm_addr_y = 0, frm_addr_uv = 0;
u32 frm0_addr_y = 0, frm0_addr_uv = 0;
u32 frm1_addr_y = 0, frm1_addr_uv = 0;
@@ -4245,13 +4340,15 @@ static void rkcif_check_buffer_update_pingpong(struct rkcif_stream *stream,
int frame_phase = 0;
bool is_dual_update_buf = false;
if (stream->state != RKCIF_STATE_STREAMING ||
rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT ||
rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO)
return;
spin_lock_irqsave(&stream->vbq_lock, flags);
if (stream->state == RKCIF_STATE_STREAMING &&
((stream->curr_buf == stream->next_buf &&
stream->cif_fmt_in->field != V4L2_FIELD_INTERLACED &&
(!dummy_buf->vaddr)) ||
stream->curr_buf == NULL ||
stream->next_buf == NULL)) {
if (stream->curr_buf == stream->next_buf ||
stream->curr_buf == NULL ||
stream->next_buf == NULL) {
frame_phase = stream->frame_phase_cache;
if (!stream->is_line_wake_up ||
(stream->is_line_wake_up && stream->frame_idx < 2)) {
@@ -4288,19 +4385,14 @@ static void rkcif_check_buffer_update_pingpong(struct rkcif_stream *stream,
if (buffer && is_dual_update_buf)
stream->next_buf = buffer;
} else if (frame_phase == CIF_CSI_FRAME1_READY) {
if (stream->next_buf == NULL &&
stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
stream->next_buf = stream->curr_buf;
} else {
stream->next_buf = list_first_entry(&stream->buf_head,
struct rkcif_buffer, queue);
if (stream->next_buf) {
list_del(&stream->next_buf->queue);
buffer = stream->next_buf;
}
if (buffer && is_dual_update_buf)
stream->curr_buf = buffer;
stream->next_buf = list_first_entry(&stream->buf_head,
struct rkcif_buffer, queue);
if (stream->next_buf) {
list_del(&stream->next_buf->queue);
buffer = stream->next_buf;
}
if (buffer && is_dual_update_buf)
stream->curr_buf = buffer;
}
} else {
v4l2_info(&dev->v4l2_dev, "%s %d\n", __func__, __LINE__);
@@ -8703,7 +8795,8 @@ static void rkcif_buf_done_prepare(struct rkcif_stream *stream,
stream->readout.wk_timestamp = vb_done->vb2_buf.timestamp;
spin_unlock_irqrestore(&stream->fps_lock, flags);
}
if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED)
if (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT ||
rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO)
vb_done->sequence /= 2;
if (stream->cur_skip_frame) {
rkcif_buf_queue(&active_buf->vb.vb2_buf);
@@ -8721,9 +8814,9 @@ static void rkcif_buf_done_prepare(struct rkcif_stream *stream,
}
if (cif_dev->hdr.hdr_mode == NO_HDR || cif_dev->hdr.hdr_mode == HDR_COMPR) {
if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
if (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT ||
rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO) {
if (stream->frame_phase == CIF_CSI_FRAME1_READY && active_buf) {
if (cif_dev->is_support_tools && stream->tools_vdev)
rkcif_buf_done_with_tools(stream, active_buf);
else
@@ -8803,6 +8896,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;
@@ -8984,6 +9140,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)
@@ -9267,7 +9499,8 @@ static int rkcif_do_reset_work(struct rkcif_device *cif_dev,
for (i = 0; i < j; i++) {
stream = resume_stream[i];
stream->fs_cnt_in_single_frame = 0;
if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
if (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT ||
rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO) {
if (stream->curr_buf == stream->next_buf) {
if (stream->curr_buf)
list_add_tail(&stream->curr_buf->queue, &stream->buf_head);
@@ -10709,7 +10942,8 @@ int rkcif_stream_resume(struct rkcif_device *cif_dev, int mode)
stream->is_single_cap = true;
spin_lock_irqsave(&stream->vbq_lock, flags);
if (!priv || priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AIQ) {
if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) {
if (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT ||
rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO) {
if (stream->curr_buf == stream->next_buf) {
if (stream->curr_buf)
list_add_tail(&stream->curr_buf->queue, &stream->buf_head);
@@ -10921,6 +11155,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)
{
@@ -11068,8 +11447,12 @@ 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 (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO)
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",
@@ -11173,6 +11556,8 @@ 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 (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO)
rkcif_check_mipi_interlaced_frame_id(stream);
}
if (intstat & CSI_LINE_INTSTAT_V1(i)) {
stream = &cif_dev->stream[i];
@@ -11186,6 +11571,8 @@ 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 (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO)
rkcif_line_wake_up_interlace(stream, stream->id);
else
rkcif_line_wake_up(stream, stream->id);
rkcif_modify_line_int(stream, false);
@@ -11388,7 +11775,10 @@ 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 (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO)
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) {
@@ -11416,12 +11806,17 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
spin_unlock_irqrestore(&stream->fps_lock, flags);
}
stream->is_in_vblank = false;
if (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO)
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 (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO)
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;
}

View File

@@ -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,
};
@@ -1954,6 +2054,11 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int
INIT_WORK(&cif_dev->sensor_work.work, rkcif_set_sensor_stream);
INIT_DELAYED_WORK(&cif_dev->work_deal_err, rkcif_deal_err_intr);
if (cif_dev->inf_id == RKCIF_MIPI_LVDS && cif_dev->chip_id <= CHIP_RK3562_CIF)
cif_dev->use_hw_interlace = false;
else
cif_dev->use_hw_interlace = true;
if (cif_dev->chip_id < CHIP_RV1126_CIF) {
if (cif_dev->inf_id == RKCIF_MIPI_LVDS) {
rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID0);

View File

@@ -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 {
@@ -834,6 +839,13 @@ struct rkcif_sensor_work {
int on;
};
enum rkcif_interlace_mode {
RKCIF_INTERLACE_NONE,
RKCIF_INTERLACE_SOFT,
RKCIF_INTERLACE_SOFT_AUTO,
RKCIF_INTERLACE_HW,
};
/*
* struct rkcif_device - ISP platform device
* @base_addr: base register address
@@ -910,6 +922,7 @@ struct rkcif_device {
bool is_aov_reserved;
bool sensor_state_change;
bool is_toisp_reset;
bool use_hw_interlace;
int rdbk_debug;
struct rkcif_sync_cfg sync_cfg;
int sditf_cnt;

View File

@@ -14,7 +14,7 @@
#define SKYHIGH_STATUS_ECC_UNCOR_ERROR (3 << 4)
static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 8, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
@@ -83,7 +83,7 @@ static const struct spinand_info skyhigh_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
0,
SPINAND_ECCINFO(&s35ml04g3_ooblayout, s35ml0xg3_ecc_get_status)),
SPINAND_INFO("S35ML02G3",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
@@ -92,7 +92,7 @@ static const struct spinand_info skyhigh_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
0,
SPINAND_ECCINFO(&s35ml04g3_ooblayout, s35ml0xg3_ecc_get_status)),
SPINAND_INFO("S35ML04G3",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
@@ -101,7 +101,7 @@ static const struct spinand_info skyhigh_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
0,
SPINAND_ECCINFO(&s35ml04g3_ooblayout, s35ml0xg3_ecc_get_status)),
};