From 82cb10f7bc9d66905399d3d27fa8c65589bf184e Mon Sep 17 00:00:00 2001 From: Allon Huang Date: Thu, 4 Mar 2021 20:02:23 +0800 Subject: [PATCH] media: platform: rockchip: cif: support bt656/bt1120 multi channels function Signed-off-by: Allon Huang Change-Id: I0eb7c4d2a9d5d99eb69627741febedc09133ff21 Signed-off-by: Zefa Chen --- drivers/media/platform/rockchip/cif/capture.c | 860 +++++++++++++----- drivers/media/platform/rockchip/cif/dev.c | 103 ++- drivers/media/platform/rockchip/cif/dev.h | 13 +- drivers/media/platform/rockchip/cif/hw.c | 12 + drivers/media/platform/rockchip/cif/regs.h | 91 +- drivers/media/platform/rockchip/cif/version.h | 2 + include/uapi/linux/rk-camera-module.h | 27 + include/uapi/linux/rkcif-config.h | 2 +- 8 files changed, 835 insertions(+), 275 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 2926de0b2096..db966f92d72c 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -38,6 +38,9 @@ #define CIF_TIMEOUT_FRAME_NUM (2) +#define CIF_DVP_PCLK_DUAL_EDGE (V4L2_MBUS_PCLK_SAMPLE_RISING |\ + V4L2_MBUS_PCLK_SAMPLE_FALLING) + /* * Round up height when allocate memory so that Rockchip encoder can * use DMA buffer directly, though this may waste a bit of memory. @@ -984,6 +987,106 @@ static enum cif_reg_index get_reg_index_of_lvds_sav_eav_blk1(int channel_id) return index; } +static enum cif_reg_index get_dvp_reg_index_of_frm0_y_addr(int channel_id) +{ + enum cif_reg_index index; + + switch (channel_id) { + case 0: + index = CIF_REG_DVP_FRM0_ADDR_Y; + break; + case 1: + index = CIF_REG_DVP_FRM0_ADDR_Y_ID1; + break; + case 2: + index = CIF_REG_DVP_FRM0_ADDR_Y_ID2; + break; + case 3: + index = CIF_REG_DVP_FRM0_ADDR_Y_ID3; + break; + default: + index = CIF_REG_DVP_FRM0_ADDR_Y; + break; + } + + return index; +} + +static enum cif_reg_index get_dvp_reg_index_of_frm1_y_addr(int channel_id) +{ + enum cif_reg_index index; + + switch (channel_id) { + case 0: + index = CIF_REG_DVP_FRM1_ADDR_Y; + break; + case 1: + index = CIF_REG_DVP_FRM1_ADDR_Y_ID1; + break; + case 2: + index = CIF_REG_DVP_FRM1_ADDR_Y_ID2; + break; + case 3: + index = CIF_REG_DVP_FRM1_ADDR_Y_ID3; + break; + default: + index = CIF_REG_DVP_FRM0_ADDR_Y; + break; + } + + return index; +} + +static enum cif_reg_index get_dvp_reg_index_of_frm0_uv_addr(int channel_id) +{ + enum cif_reg_index index; + + switch (channel_id) { + case 0: + index = CIF_REG_DVP_FRM0_ADDR_UV; + break; + case 1: + index = CIF_REG_DVP_FRM0_ADDR_UV_ID1; + break; + case 2: + index = CIF_REG_DVP_FRM0_ADDR_UV_ID2; + break; + case 3: + index = CIF_REG_DVP_FRM0_ADDR_UV_ID3; + break; + default: + index = CIF_REG_DVP_FRM0_ADDR_UV; + break; + } + + return index; +} + +static enum cif_reg_index get_dvp_reg_index_of_frm1_uv_addr(int channel_id) +{ + enum cif_reg_index index; + + switch (channel_id) { + case 0: + index = CIF_REG_DVP_FRM1_ADDR_UV; + break; + case 1: + index = CIF_REG_DVP_FRM1_ADDR_UV_ID1; + break; + case 2: + index = CIF_REG_DVP_FRM1_ADDR_UV_ID2; + break; + case 3: + index = CIF_REG_DVP_FRM1_ADDR_UV_ID3; + break; + default: + index = CIF_REG_DVP_FRM1_ADDR_UV; + break; + } + + return index; +} + /***************************** stream operations ******************************/ static void rkcif_assign_new_buffer_oneframe(struct rkcif_stream *stream, enum rkcif_yuvaddr_state stat) @@ -1082,126 +1185,174 @@ static void rkcif_assign_new_buffer_oneframe(struct rkcif_stream *stream, spin_unlock(&stream->vbq_lock); } -static void rkcif_assign_new_buffer_pingpong(struct rkcif_stream *stream, - int init, int csi_ch) +static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream, + int channel_id) { - struct rkcif_dummy_buffer *dummy_buf = &stream->dummy_buf; struct rkcif_device *dev = stream->cifdev; + struct rkcif_dummy_buffer *dummy_buf = &stream->dummy_buf; + struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; + u32 frm0_addr_y, frm0_addr_uv; + u32 frm1_addr_y, frm1_addr_uv; + + if (mbus_cfg->type == V4L2_MBUS_CSI2 || + mbus_cfg->type == V4L2_MBUS_CCP2) { + frm0_addr_y = get_reg_index_of_frm0_y_addr(channel_id); + frm0_addr_uv = get_reg_index_of_frm0_uv_addr(channel_id); + frm1_addr_y = get_reg_index_of_frm1_y_addr(channel_id); + frm1_addr_uv = get_reg_index_of_frm1_uv_addr(channel_id); + } else { + frm0_addr_y = get_dvp_reg_index_of_frm0_y_addr(channel_id); + frm0_addr_uv = get_dvp_reg_index_of_frm0_uv_addr(channel_id); + frm1_addr_y = get_dvp_reg_index_of_frm1_y_addr(channel_id); + frm1_addr_uv = get_dvp_reg_index_of_frm1_uv_addr(channel_id); + } + + spin_lock(&stream->vbq_lock); + + 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); + } + } + + if (stream->curr_buf) { + rkcif_write_register(dev, frm0_addr_y, + stream->curr_buf->buff_addr[RKCIF_PLANE_Y]); + 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 { + 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->next_buf) { + if (!list_empty(&stream->buf_head)) { + stream->next_buf = list_first_entry(&stream->buf_head, + struct rkcif_buffer, queue); + list_del(&stream->next_buf->queue); + } + } + + if (stream->next_buf) { + rkcif_write_register(dev, frm1_addr_y, + stream->next_buf->buff_addr[RKCIF_PLANE_Y]); + 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 { + 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); + } + + stream->is_dvp_yuv_addr_init = true; + + /* for BT.656/BT.1120 multi channels function, + * yuv addr of unused channel must be set + */ + if (mbus_cfg->type == V4L2_MBUS_BT656) { + int ch_id; + + for (ch_id = 0; ch_id < RKCIF_MAX_STREAM_DVP; ch_id++) { + if (dev->stream[ch_id].is_dvp_yuv_addr_init) + continue; + + rkcif_write_register(dev, + get_dvp_reg_index_of_frm0_y_addr(ch_id), + dummy_buf->dma_addr); + rkcif_write_register(dev, + get_dvp_reg_index_of_frm1_y_addr(ch_id), + dummy_buf->dma_addr); + rkcif_write_register(dev, + get_dvp_reg_index_of_frm0_uv_addr(ch_id), + dummy_buf->dma_addr); + rkcif_write_register(dev, + get_dvp_reg_index_of_frm1_uv_addr(ch_id), + dummy_buf->dma_addr); + } + } + + spin_unlock(&stream->vbq_lock); +} + +static void rkcif_assign_new_buffer_update(struct rkcif_stream *stream, + int channel_id) +{ + struct rkcif_device *dev = stream->cifdev; + struct rkcif_dummy_buffer *dummy_buf = &stream->dummy_buf; struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; struct rkcif_buffer *buffer = NULL; u32 frm_addr_y, frm_addr_uv; - if (init) { - u32 frm0_addr_y, frm0_addr_uv; - u32 frm1_addr_y, frm1_addr_uv; - - if (mbus_cfg->type == V4L2_MBUS_CSI2 || - mbus_cfg->type == V4L2_MBUS_CCP2) { - frm0_addr_y = get_reg_index_of_frm0_y_addr(csi_ch); - frm0_addr_uv = get_reg_index_of_frm0_uv_addr(csi_ch); - frm1_addr_y = get_reg_index_of_frm1_y_addr(csi_ch); - frm1_addr_uv = get_reg_index_of_frm1_uv_addr(csi_ch); - } else { - frm0_addr_y = CIF_REG_DVP_FRM0_ADDR_Y; - frm0_addr_uv = CIF_REG_DVP_FRM0_ADDR_UV; - frm1_addr_y = CIF_REG_DVP_FRM1_ADDR_Y; - frm1_addr_uv = CIF_REG_DVP_FRM1_ADDR_UV; - } - - spin_lock(&stream->vbq_lock); - 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); - } - } - - if (stream->curr_buf) { - rkcif_write_register(dev, frm0_addr_y, - stream->curr_buf->buff_addr[RKCIF_PLANE_Y]); - 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 { - 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->next_buf) { - if (!list_empty(&stream->buf_head)) { - stream->next_buf = list_first_entry(&stream->buf_head, - struct rkcif_buffer, queue); - list_del(&stream->next_buf->queue); - } - } - - if (stream->next_buf) { - rkcif_write_register(dev, frm1_addr_y, - stream->next_buf->buff_addr[RKCIF_PLANE_Y]); - 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 { - 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(&stream->vbq_lock); + if (mbus_cfg->type == V4L2_MBUS_CSI2 || + mbus_cfg->type == V4L2_MBUS_CCP2) { + frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ? + get_reg_index_of_frm0_y_addr(channel_id) : + get_reg_index_of_frm1_y_addr(channel_id); + frm_addr_uv = stream->frame_phase & CIF_CSI_FRAME0_READY ? + get_reg_index_of_frm0_uv_addr(channel_id) : + get_reg_index_of_frm1_uv_addr(channel_id); } else { - if (mbus_cfg->type == V4L2_MBUS_CSI2 || - mbus_cfg->type == V4L2_MBUS_CCP2) { - frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ? - get_reg_index_of_frm0_y_addr(csi_ch) : - get_reg_index_of_frm1_y_addr(csi_ch); - frm_addr_uv = stream->frame_phase & CIF_CSI_FRAME0_READY ? - get_reg_index_of_frm0_uv_addr(csi_ch) : - get_reg_index_of_frm1_uv_addr(csi_ch); - } else { - frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ? - CIF_FRM0_ADDR_Y : CIF_FRM1_ADDR_Y; - frm_addr_uv = stream->frame_phase & CIF_CSI_FRAME0_READY ? - CIF_FRM0_ADDR_UV : CIF_FRM1_ADDR_UV; - } - - spin_lock(&stream->vbq_lock); - if (!list_empty(&stream->buf_head)) { - if (stream->frame_phase == CIF_CSI_FRAME0_READY) { - stream->curr_buf = list_first_entry(&stream->buf_head, - struct rkcif_buffer, queue); - list_del(&stream->curr_buf->queue); - buffer = stream->curr_buf; - } else if (stream->frame_phase == CIF_CSI_FRAME1_READY) { - stream->next_buf = list_first_entry(&stream->buf_head, - struct rkcif_buffer, queue); - list_del(&stream->next_buf->queue); - buffer = stream->next_buf; - } - } else { - 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; - buffer = NULL; - } - spin_unlock(&stream->vbq_lock); - - if (buffer) { - rkcif_write_register(dev, frm_addr_y, - buffer->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm_addr_uv, - buffer->buff_addr[RKCIF_PLANE_CBCR]); - } else { - 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); - v4l2_info(&dev->v4l2_dev, - "frame drop to dummy buf, stream id %d\n", stream->id); - } + frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ? + get_dvp_reg_index_of_frm0_y_addr(channel_id) : + get_dvp_reg_index_of_frm1_y_addr(channel_id); + frm_addr_uv = stream->frame_phase & CIF_CSI_FRAME0_READY ? + get_dvp_reg_index_of_frm0_uv_addr(channel_id) : + get_dvp_reg_index_of_frm1_uv_addr(channel_id); } + + spin_lock(&stream->vbq_lock); + if (!list_empty(&stream->buf_head)) { + if (stream->frame_phase == CIF_CSI_FRAME0_READY) { + stream->curr_buf = list_first_entry(&stream->buf_head, + struct rkcif_buffer, queue); + list_del(&stream->curr_buf->queue); + buffer = stream->curr_buf; + } else if (stream->frame_phase == CIF_CSI_FRAME1_READY) { + stream->next_buf = list_first_entry(&stream->buf_head, + struct rkcif_buffer, queue); + list_del(&stream->next_buf->queue); + buffer = stream->next_buf; + } + } else { + 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; + buffer = NULL; + } + spin_unlock(&stream->vbq_lock); + + if (buffer) { + rkcif_write_register(dev, frm_addr_y, + buffer->buff_addr[RKCIF_PLANE_Y]); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, + buffer->buff_addr[RKCIF_PLANE_CBCR]); + } else { + 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); + v4l2_info(&dev->v4l2_dev, + "frame drop to dummy buf, %s stream[%d]\n", + (mbus_cfg->type == V4L2_MBUS_CSI2 || + mbus_cfg->type == V4L2_MBUS_CCP2) ? "mipi/lvds" : "dvp", + stream->id); + } +} + +static void rkcif_assign_new_buffer_pingpong(struct rkcif_stream *stream, + int init, int channel_id) +{ + if (init) + rkcif_assign_new_buffer_init(stream, channel_id); + else + rkcif_assign_new_buffer_update(stream, channel_id); } static void rkcif_csi_get_vc_num(struct rkcif_device *dev, @@ -1456,7 +1607,9 @@ 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, 1, channel->id); + rkcif_assign_new_buffer_pingpong(stream, + RKCIF_YUV_ADDR_STATE_INIT, + channel->id); if (mbus_type == V4L2_MBUS_CSI2) { val = CSI_ENABLE_CAPTURE | channel->fmt_val | @@ -1859,6 +2012,7 @@ static void rkcif_stop_streaming(struct vb2_queue *queue) ret); dev->is_start_hdr = false; + stream->is_dvp_yuv_addr_init = false; /* release buffers */ if (stream->curr_buf) @@ -2180,8 +2334,12 @@ int rkcif_update_sensor_info(struct rkcif_stream *stream) } ret = v4l2_subdev_call(sensor->sd, video, g_mbus_config, &sensor->mbus); - if (ret && ret != -ENOIOCTLCMD) + if (ret && ret != -ENOIOCTLCMD) { + v4l2_err(&stream->cifdev->v4l2_dev, + "%s: get remote %s mbus failed!\n", __func__, sensor->sd->name); return ret; + } + stream->cifdev->active_sensor = sensor; terminal_sensor = &stream->cifdev->terminal_sensor; @@ -2189,29 +2347,36 @@ int rkcif_update_sensor_info(struct rkcif_stream *stream) if (terminal_sensor->sd) { ret = v4l2_subdev_call(terminal_sensor->sd, video, g_mbus_config, &terminal_sensor->mbus); - if (ret && ret != -ENOIOCTLCMD) + if (ret && ret != -ENOIOCTLCMD) { + v4l2_err(&stream->cifdev->v4l2_dev, + "%s: get terminal %s mbus failed!\n", + __func__, terminal_sensor->sd->name); return ret; + } } - switch (terminal_sensor->mbus.flags & V4L2_MBUS_CSI2_LANES) { - case V4L2_MBUS_CSI2_1_LANE: - terminal_sensor->lanes = 1; - break; - case V4L2_MBUS_CSI2_2_LANE: - terminal_sensor->lanes = 2; - break; - case V4L2_MBUS_CSI2_3_LANE: - terminal_sensor->lanes = 3; - break; - case V4L2_MBUS_CSI2_4_LANE: - terminal_sensor->lanes = 4; - break; - default: - v4l2_err(&stream->cifdev->v4l2_dev, "%s:get sd:%s lane num failed!\n", - __func__, - terminal_sensor->sd ? - terminal_sensor->sd->name : "null"); - return -EINVAL; + if (terminal_sensor->mbus.type == V4L2_MBUS_CSI2 || + terminal_sensor->mbus.type == V4L2_MBUS_CCP2) { + switch (terminal_sensor->mbus.flags & V4L2_MBUS_CSI2_LANES) { + case V4L2_MBUS_CSI2_1_LANE: + terminal_sensor->lanes = 1; + break; + case V4L2_MBUS_CSI2_2_LANE: + terminal_sensor->lanes = 2; + break; + case V4L2_MBUS_CSI2_3_LANE: + terminal_sensor->lanes = 3; + break; + case V4L2_MBUS_CSI2_4_LANE: + terminal_sensor->lanes = 4; + break; + default: + v4l2_err(&stream->cifdev->v4l2_dev, "%s:get sd:%s lane num failed!\n", + __func__, + terminal_sensor->sd ? + terminal_sensor->sd->name : "null"); + return -EINVAL; + } } return ret; @@ -2220,21 +2385,64 @@ int rkcif_update_sensor_info(struct rkcif_stream *stream) static int rkcif_stream_start(struct rkcif_stream *stream) { u32 val, mbus_flags, href_pol, vsync_pol, - xfer_mode = 0, yc_swap = 0, - inputmode = 0, mipimode = 0, workmode = 0, + xfer_mode = 0, yc_swap = 0, inputmode = 0, + mipimode = 0, workmode = 0, multi_id = 0, multi_id_en = BT656_1120_MULTI_ID_DISABLE, multi_id_mode = BT656_1120_MULTI_ID_MODE_1, multi_id_sel = BT656_1120_MULTI_ID_SEL_LSB, - bt1120_edge_mode = BT1120_CLOCK_SINGLE_EDGES; + bt1120_edge_mode = BT1120_CLOCK_SINGLE_EDGES, + bt1120_flags = 0; + struct rkmodule_bt656_mbus_info bt1120_info; struct rkcif_device *dev = stream->cifdev; struct rkcif_sensor_info *sensor_info; + struct v4l2_mbus_config *mbus; struct rkcif_dvp_sof_subdev *sof_sd = &dev->dvp_sof_subdev; const struct cif_output_fmt *fmt; - sensor_info = dev->active_sensor; - stream->frame_idx = 0; + if (stream->state != RKCIF_STATE_RESET_IN_STREAMING) + stream->frame_idx = 0; + + sensor_info = dev->active_sensor; + mbus = &sensor_info->mbus; + + if (sensor_info->sd && mbus->type == V4L2_MBUS_BT656) { + int ret; + + multi_id_en = BT656_1120_MULTI_ID_ENABLE; + + ret = v4l2_subdev_call(sensor_info->sd, + core, ioctl, + RKMODULE_GET_BT656_MBUS_INFO, + &bt1120_info); + if (ret) { + v4l2_warn(&dev->v4l2_dev, + "waring: no muti channel info for BT.656\n"); + } else { + bt1120_flags = bt1120_info.flags; + if (bt1120_flags & RKMODULE_CAMERA_BT656_PARSE_ID_LSB) + multi_id_sel = BT656_1120_MULTI_ID_SEL_LSB; + else + multi_id_sel = BT656_1120_MULTI_ID_SEL_MSB; + + if (((bt1120_flags & RKMODULE_CAMERA_BT656_CHANNELS) >> 2) > 1) + multi_id_mode = BT656_1120_MULTI_ID_MODE_4; + else + multi_id_mode = BT656_1120_MULTI_ID_MODE_1; + + multi_id = DVP_SW_MULTI_ID(stream->id, stream->id, bt1120_info.id_en_bits); + rkcif_write_register_or(dev, CIF_REG_DVP_MULTI_ID, multi_id); + } + } + + mbus_flags = mbus->flags; + if ((mbus_flags & CIF_DVP_PCLK_DUAL_EDGE) == CIF_DVP_PCLK_DUAL_EDGE) { + bt1120_edge_mode = BT1120_CLOCK_DOUBLE_EDGES; + rkcif_enable_dvp_clk_dual_edge(dev, true); + } else { + bt1120_edge_mode = BT1120_CLOCK_SINGLE_EDGES; + rkcif_enable_dvp_clk_dual_edge(dev, false); + } - mbus_flags = sensor_info->mbus.flags; if (mbus_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) rkcif_config_dvp_clk_sampling_edge(dev, RKCIF_CLK_RISING); else @@ -2246,13 +2454,27 @@ static int rkcif_stream_start(struct rkcif_stream *stream) VSY_HIGH_ACTIVE : VSY_LOW_ACTIVE; inputmode = rkcif_determine_input_mode(stream); - if (inputmode == INPUT_MODE_BT1120) { - if (stream->cif_fmt_in->field == V4L2_FIELD_NONE) - xfer_mode = BT1120_TRANSMIT_PROGRESS; - else - xfer_mode = BT1120_TRANSMIT_INTERFACE; - if (CIF_FETCH_IS_Y_FIRST(stream->cif_fmt_in->dvp_fmt_val)) - yc_swap = BT1120_YC_SWAP; + if (dev->chip_id <= CHIP_RK1808_CIF) { + if (inputmode == INPUT_MODE_BT1120) { + if (stream->cif_fmt_in->field == V4L2_FIELD_NONE) + xfer_mode = BT1120_TRANSMIT_PROGRESS; + else + xfer_mode = BT1120_TRANSMIT_INTERFACE; + if (CIF_FETCH_IS_Y_FIRST(stream->cif_fmt_in->dvp_fmt_val)) + yc_swap = BT1120_YC_SWAP; + } + } else { + if (sensor_info->mbus.type == V4L2_MBUS_BT656) { + if (stream->cif_fmt_in->field == V4L2_FIELD_NONE) + xfer_mode = BT1120_TRANSMIT_PROGRESS; + else + xfer_mode = BT1120_TRANSMIT_INTERFACE; + } + + if (inputmode == INPUT_MODE_BT1120) { + if (CIF_FETCH_IS_Y_FIRST(stream->cif_fmt_in->dvp_fmt_val)) + yc_swap = BT1120_YC_SWAP; + } } if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2) { @@ -2306,23 +2528,24 @@ static int rkcif_stream_start(struct rkcif_stream *stream) rkcif_write_register(dev, CIF_REG_DVP_CROP, dev->channels[stream->id].crop_st_y << CIF_CROP_Y_SHIFT | dev->channels[stream->id].crop_st_x); - rkcif_write_register(dev, CIF_REG_DVP_FRAME_STATUS, FRAME_STAT_CLS); + + if (atomic_read(&dev->pipe.stream_cnt) <= 1) + rkcif_write_register(dev, CIF_REG_DVP_FRAME_STATUS, FRAME_STAT_CLS); + rkcif_write_register(dev, CIF_REG_DVP_INTSTAT, INTSTAT_CLS); rkcif_write_register(dev, CIF_REG_DVP_SCL_CTRL, rkcif_scl_ctl(stream)); - if ((dev->chip_id == CHIP_RK1808_CIF || - dev->chip_id == CHIP_RV1126_CIF || - dev->chip_id == CHIP_RK3568_CIF) && - inputmode == INPUT_MODE_BT1120) - rkcif_assign_new_buffer_pingpong(stream, 1, 0); - else - /* Set up an buffer for the next frame */ + if (dev->chip_id < CHIP_RK1808_CIF) rkcif_assign_new_buffer_oneframe(stream, RKCIF_YUV_ADDR_STATE_INIT); + else + rkcif_assign_new_buffer_pingpong(stream, + RKCIF_YUV_ADDR_STATE_INIT, + stream->id); - rkcif_write_register(dev, CIF_REG_DVP_INTEN, - FRAME_END_EN | INTSTAT_ERR | - PST_INF_FRAME_END); + rkcif_write_register_or(dev, CIF_REG_DVP_INTEN, + DVP_DMA_END_INTSTAT(stream->id) | + INTSTAT_ERR | PST_INF_FRAME_END); /* enable line int for sof */ rkcif_write_register(dev, CIF_REG_DVP_LINE_INT_NUM, 0x1); @@ -2335,18 +2558,14 @@ static int rkcif_stream_start(struct rkcif_stream *stream) else workmode = MODE_LINELOOP; - if ((dev->chip_id == CHIP_RK1808_CIF || - dev->chip_id == CHIP_RV1126_CIF || - dev->chip_id == CHIP_RK3568_CIF) && - inputmode == INPUT_MODE_BT1120) { + if (inputmode == INPUT_MODE_BT1120) { + workmode = MODE_PINGPONG; dev->workmode = RKCIF_WORKMODE_PINGPONG; - rkcif_write_register(dev, CIF_REG_DVP_CTRL, - AXI_BURST_16 | MODE_PINGPONG | ENABLE_CAPTURE); - } else { - rkcif_write_register(dev, CIF_REG_DVP_CTRL, - AXI_BURST_16 | workmode | ENABLE_CAPTURE); } + rkcif_write_register(dev, CIF_REG_DVP_CTRL, + AXI_BURST_16 | workmode | ENABLE_CAPTURE); + atomic_set(&sof_sd->frm_sync_seq, 0); stream->state = RKCIF_STATE_STREAMING; stream->cifdev->dvp_sof_in_oneframe = 0; @@ -2447,10 +2666,7 @@ static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count) goto runtime_put; } - if (dev->chip_id == CHIP_RK1808_CIF || - dev->chip_id == CHIP_RV1126_CIF || - dev->chip_id == CHIP_RV1126_CIF_LITE || - dev->chip_id == CHIP_RK3568_CIF) { + if (dev->chip_id >= CHIP_RK1808_CIF) { if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2 || dev->active_sensor->mbus.type == V4L2_MBUS_CCP2) ret = rkcif_csi_stream_start(stream); @@ -2738,6 +2954,8 @@ void rkcif_stream_init(struct rkcif_device *dev, u32 id) else stream->extend_line.is_extended = false; + stream->is_dvp_yuv_addr_init = false; + } static int rkcif_fh_open(struct file *filp) @@ -3189,29 +3407,69 @@ static int rkcif_register_stream_vdev(struct rkcif_stream *stream, int ret = 0; char *vdev_name; - if (is_multi_input) { - switch (stream->id) { - case RKCIF_STREAM_MIPI_ID0: - vdev_name = CIF_MIPI_ID0_VDEV_NAME; - break; - case RKCIF_STREAM_MIPI_ID1: - vdev_name = CIF_MIPI_ID1_VDEV_NAME; - break; - case RKCIF_STREAM_MIPI_ID2: - vdev_name = CIF_MIPI_ID2_VDEV_NAME; - break; - case RKCIF_STREAM_MIPI_ID3: - vdev_name = CIF_MIPI_ID3_VDEV_NAME; - break; - case RKCIF_STREAM_DVP: - vdev_name = CIF_DVP_VDEV_NAME; - break; - default: - v4l2_err(v4l2_dev, "Invalid stream\n"); - goto unreg; + if (dev->chip_id < CHIP_RV1126_CIF) { + if (is_multi_input) { + switch (stream->id) { + case RKCIF_STREAM_MIPI_ID0: + vdev_name = CIF_MIPI_ID0_VDEV_NAME; + break; + case RKCIF_STREAM_MIPI_ID1: + vdev_name = CIF_MIPI_ID1_VDEV_NAME; + break; + case RKCIF_STREAM_MIPI_ID2: + vdev_name = CIF_MIPI_ID2_VDEV_NAME; + break; + case RKCIF_STREAM_MIPI_ID3: + vdev_name = CIF_MIPI_ID3_VDEV_NAME; + break; + case RKCIF_STREAM_DVP: + vdev_name = CIF_DVP_VDEV_NAME; + break; + default: + v4l2_err(v4l2_dev, "Invalid stream\n"); + goto unreg; + } + } else { + vdev_name = CIF_VIDEODEVICE_NAME; } } else { - vdev_name = CIF_VIDEODEVICE_NAME; + if (dev->inf_id == RKCIF_MIPI_LVDS) { + switch (stream->id) { + case RKCIF_STREAM_MIPI_ID0: + vdev_name = CIF_MIPI_ID0_VDEV_NAME; + break; + case RKCIF_STREAM_MIPI_ID1: + vdev_name = CIF_MIPI_ID1_VDEV_NAME; + break; + case RKCIF_STREAM_MIPI_ID2: + vdev_name = CIF_MIPI_ID2_VDEV_NAME; + break; + case RKCIF_STREAM_MIPI_ID3: + vdev_name = CIF_MIPI_ID3_VDEV_NAME; + break; + default: + v4l2_err(v4l2_dev, "Invalid stream\n"); + goto unreg; + } + } else { + switch (stream->id) { + case RKCIF_STREAM_MIPI_ID0: + vdev_name = CIF_DVP_ID0_VDEV_NAME; + break; + case RKCIF_STREAM_MIPI_ID1: + vdev_name = CIF_DVP_ID1_VDEV_NAME; + break; + case RKCIF_STREAM_MIPI_ID2: + vdev_name = CIF_DVP_ID2_VDEV_NAME; + break; + case RKCIF_STREAM_MIPI_ID3: + vdev_name = CIF_DVP_ID3_VDEV_NAME; + break; + default: + v4l2_err(v4l2_dev, "Invalid stream\n"); + goto unreg; + } + } } strlcpy(vdev->name, vdev_name, sizeof(vdev->name)); @@ -3761,7 +4019,7 @@ void rkcif_irq_oneframe(struct rkcif_device *cif_dev) } static int rkcif_csi_g_mipi_id(struct v4l2_device *v4l2_dev, - unsigned int intstat) + unsigned int intstat) { if (intstat & CSI_FRAME_END_ID0) { if ((intstat & CSI_FRAME_END_ID0) == @@ -3794,6 +4052,46 @@ static int rkcif_csi_g_mipi_id(struct v4l2_device *v4l2_dev, return -EINVAL; } +static int rkcif_dvp_g_ch_id(struct v4l2_device *v4l2_dev, + u32 *intstat, u32 frm_stat) +{ + if (*intstat & DVP_FRAME_END_ID0) { + if ((frm_stat & DVP_CHANNEL0_FRM_READ) == + DVP_CHANNEL0_FRM_READ) + v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in DVP ID0\n"); + + *intstat &= ~DVP_FRAME_END_ID0; + return RKCIF_STREAM_MIPI_ID0; + } + + if (*intstat & DVP_FRAME_END_ID1) { + if ((frm_stat & DVP_CHANNEL1_FRM_READ) == + DVP_CHANNEL1_FRM_READ) + v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in DVP ID1\n"); + + *intstat &= ~DVP_FRAME_END_ID1; + return RKCIF_STREAM_MIPI_ID1; + } + + if (*intstat & DVP_FRAME_END_ID2) { + if ((frm_stat & DVP_CHANNEL2_FRM_READ) == + DVP_CHANNEL2_FRM_READ) + v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in DVP ID2\n"); + *intstat &= ~DVP_FRAME_END_ID2; + return RKCIF_STREAM_MIPI_ID2; + } + + if (*intstat & DVP_FRAME_END_ID3) { + if ((frm_stat & DVP_CHANNEL3_FRM_READ) == + DVP_CHANNEL3_FRM_READ) + v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in DVP ID3\n"); + *intstat &= ~DVP_FRAME_END_ID3; + return RKCIF_STREAM_MIPI_ID3; + } + + return -EINVAL; +} + static bool rkcif_is_csi2_err_trigger_reset(struct rkcif_timer *timer) { struct rkcif_device *dev = container_of(timer, @@ -4105,7 +4403,9 @@ static void rkcif_update_stream(struct rkcif_device *cif_dev, spin_unlock(&stream->fps_lock); cif_dev->buf_wake_up_cnt += 1; - rkcif_assign_new_buffer_pingpong(stream, 0, mipi_id); + rkcif_assign_new_buffer_pingpong(stream, + RKCIF_YUV_ADDR_STATE_UPDATE, + mipi_id); if (cif_dev->chip_id == CHIP_RV1126_CIF || cif_dev->chip_id == CHIP_RV1126_CIF_LITE || @@ -4708,6 +5008,7 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev) u32 lastline, lastpix, ctl; u32 cif_frmst, frmid, int_en; struct rkcif_stream *stream; + int ch_id; intstat = rkcif_read_register(cif_dev, CIF_REG_DVP_INTSTAT); cif_frmst = rkcif_read_register(cif_dev, CIF_REG_DVP_FRAME_STATUS); @@ -4767,74 +5068,131 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev) * a frame ready */ if ((intstat & PST_INF_FRAME_END)) { - + stream = &cif_dev->stream[RKCIF_STREAM_CIF]; if (stream->stopping) /* To stop CIF ASAP, before FRAME_END irq */ rkcif_write_register(cif_dev, CIF_REG_DVP_CTRL, ctl & (~ENABLE_CAPTURE)); } - if ((intstat & FRAME_END)) { - struct vb2_v4l2_buffer *vb_done = NULL; + if (cif_dev->chip_id <= CHIP_RK1808_CIF) { - int_en = rkcif_read_register(cif_dev, CIF_REG_DVP_INTEN); - int_en |= LINE_INT_EN; - rkcif_write_register(cif_dev, CIF_REG_DVP_INTEN, int_en); - cif_dev->dvp_sof_in_oneframe = 0; + stream = &cif_dev->stream[RKCIF_STREAM_CIF]; - if (stream->stopping) { - rkcif_stream_stop(stream); - stream->stopping = false; - wake_up(&stream->wq_stopped); - return; + if ((intstat & FRAME_END)) { + struct vb2_v4l2_buffer *vb_done = NULL; + + int_en = rkcif_read_register(cif_dev, CIF_REG_DVP_INTEN); + int_en |= LINE_INT_EN; + rkcif_write_register(cif_dev, CIF_REG_DVP_INTEN, int_en); + cif_dev->dvp_sof_in_oneframe = 0; + + if (stream->stopping) { + rkcif_stream_stop(stream); + stream->stopping = false; + wake_up(&stream->wq_stopped); + return; + } + + frmid = CIF_GET_FRAME_ID(cif_frmst); + if ((cif_frmst == 0xfffd0002) || (cif_frmst == 0xfffe0002)) { + v4l2_info(&cif_dev->v4l2_dev, "frmid:%d, frmstat:0x%x\n", + frmid, cif_frmst); + rkcif_write_register(cif_dev, CIF_REG_DVP_FRAME_STATUS, + FRAME_STAT_CLS); + } + + if (lastline != stream->pixm.height || + (!(cif_frmst & CIF_F0_READY) && + !(cif_frmst & CIF_F1_READY))) { + + cif_dev->dvp_sof_in_oneframe = 1; + v4l2_err(&cif_dev->v4l2_dev, + "Bad frame, pp irq:0x%x frmst:0x%x size:%dx%d\n", + intstat, cif_frmst, lastpix, lastline); + return; + } + + if (cif_frmst & CIF_F0_READY) { + if (stream->curr_buf) + vb_done = &stream->curr_buf->vb; + stream->frame_phase = CIF_CSI_FRAME0_READY; + } else if (cif_frmst & CIF_F1_READY) { + if (stream->next_buf) + vb_done = &stream->next_buf->vb; + stream->frame_phase = CIF_CSI_FRAME1_READY; + } + + spin_lock(&stream->fps_lock); + 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(&stream->fps_lock); + + rkcif_assign_new_buffer_oneframe(stream, + RKCIF_YUV_ADDR_STATE_UPDATE); + + if (vb_done) { + vb_done->sequence = stream->frame_idx; + rkcif_vb_done_oneframe(stream, vb_done); + } + + stream->frame_idx++; + cif_dev->irq_stats.all_frm_end_cnt++; } + } else { + for (i = 0; i < RKCIF_MAX_STREAM_DVP; i++) { + ch_id = rkcif_dvp_g_ch_id(&cif_dev->v4l2_dev, &intstat, cif_frmst); - frmid = CIF_GET_FRAME_ID(cif_frmst); - if ((cif_frmst == 0xfffd0002) || (cif_frmst == 0xfffe0002)) { - v4l2_info(&cif_dev->v4l2_dev, "frmid:%d, frmstat:0x%x\n", - frmid, cif_frmst); - rkcif_write_register(cif_dev, CIF_REG_DVP_FRAME_STATUS, - FRAME_STAT_CLS); + if (ch_id < 0) + continue; + + if (ch_id == RKCIF_STREAM_MIPI_ID0) { + int_en = rkcif_read_register(cif_dev, CIF_REG_DVP_INTEN); + int_en |= LINE_INT_EN; + rkcif_write_register(cif_dev, CIF_REG_DVP_INTEN, int_en); + cif_dev->dvp_sof_in_oneframe = 0; + } + + stream = &cif_dev->stream[ch_id]; + + if (stream->stopping) { + rkcif_stream_stop(stream); + stream->stopping = false; + wake_up(&stream->wq_stopped); + continue; + } + + if (stream->state != RKCIF_STATE_STREAMING) + continue; + + switch (ch_id) { + case RKCIF_STREAM_MIPI_ID0: + stream->frame_phase = DVP_FRM_STS_ID0(cif_frmst); + break; + case RKCIF_STREAM_MIPI_ID1: + stream->frame_phase = DVP_FRM_STS_ID1(cif_frmst); + break; + case RKCIF_STREAM_MIPI_ID2: + stream->frame_phase = DVP_FRM_STS_ID2(cif_frmst); + break; + case RKCIF_STREAM_MIPI_ID3: + stream->frame_phase = DVP_FRM_STS_ID3(cif_frmst); + break; + } + + + frmid = CIF_GET_FRAME_ID(cif_frmst); + if ((frmid == 0xfffd) || (frmid == 0xfffe)) { + v4l2_info(&cif_dev->v4l2_dev, "frmid:%d, frmstat:0x%x\n", + frmid, cif_frmst); + rkcif_write_register(cif_dev, CIF_REG_DVP_FRAME_STATUS, + FRAME_STAT_CLS); + } + rkcif_update_stream(cif_dev, stream, ch_id); + cif_dev->irq_stats.all_frm_end_cnt++; } - - if (lastline != stream->pixm.height || - (!(cif_frmst & CIF_F0_READY) && - !(cif_frmst & CIF_F1_READY))) { - - cif_dev->dvp_sof_in_oneframe = 1; - v4l2_err(&cif_dev->v4l2_dev, - "Bad frame, pp irq:0x%x frmst:0x%x size:%dx%d\n", - intstat, cif_frmst, lastpix, lastline); - return; - } - - if (cif_frmst & CIF_F0_READY) { - if (stream->curr_buf) - vb_done = &stream->curr_buf->vb; - stream->frame_phase = CIF_CSI_FRAME0_READY; - } else if (cif_frmst & CIF_F1_READY) { - if (stream->next_buf) - vb_done = &stream->next_buf->vb; - stream->frame_phase = CIF_CSI_FRAME1_READY; - } - - spin_lock(&stream->fps_lock); - 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(&stream->fps_lock); - - rkcif_assign_new_buffer_oneframe(stream, - RKCIF_YUV_ADDR_STATE_UPDATE); - - if (vb_done) { - vb_done->sequence = stream->frame_idx; - rkcif_vb_done_oneframe(stream, vb_done); - } - - stream->frame_idx++; - cif_dev->irq_stats.all_frm_end_cnt++; } } } diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index eedf767dc5e7..3c826ff413d6 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -224,6 +224,32 @@ u32 rkcif_read_grf_reg(struct rkcif_device *dev, enum cif_reg_index index) return val; } +void rkcif_enable_dvp_clk_dual_edge(struct rkcif_device *dev, bool on) +{ + struct rkcif_hw *cif_hw = dev->hw_dev; + u32 val = 0x0; + + if (!IS_ERR(cif_hw->grf)) { + + if (dev->chip_id == CHIP_RK3568_CIF) { + if (on) + val = RK3568_CIF_PCLK_DUAL_EDGE; + else + val = RK3568_CIF_PCLK_SINGLE_EDGE; + rkcif_write_grf_reg(dev, CIF_REG_GRF_CIFIO_CON1, val); + } else if (dev->chip_id == CHIP_RV1126_CIF) { + if (on) + val = CIF_SAMPLING_EDGE_DOUBLE; + else + val = CIF_SAMPLING_EDGE_SINGLE; + rkcif_write_grf_reg(dev, CIF_REG_GRF_CIFIO_CON, val); + } + } + + v4l2_info(&dev->v4l2_dev, + "set dual edge mode(%s,0x%x)!!!\n", on ? "on" : "off", val); +} + void rkcif_config_dvp_clk_sampling_edge(struct rkcif_device *dev, enum rkcif_clk_edge edge) { @@ -431,10 +457,15 @@ static int rkcif_create_links(struct rkcif_device *dev) unsigned int s, pad, id, stream_num = 0; bool mipi_lvds_linked = false; - if (dev->inf_id == RKCIF_MIPI_LVDS) + + if (dev->chip_id < CHIP_RV1126_CIF) { + if (dev->inf_id == RKCIF_MIPI_LVDS) + stream_num = RKCIF_MAX_STREAM_MIPI; + else + stream_num = RKCIF_SINGLE_STREAM; + } else { stream_num = RKCIF_MAX_STREAM_MIPI; - else - stream_num = RKCIF_SINGLE_STREAM; + } /* sensor links(or mipi-phy) */ for (s = 0; s < dev->num_sensors; ++s) { @@ -470,9 +501,7 @@ static int rkcif_create_links(struct rkcif_device *dev) if ((linked_sensor.mbus.type == V4L2_MBUS_BT656 || linked_sensor.mbus.type == V4L2_MBUS_PARALLEL) && - (dev->chip_id == CHIP_RK1808_CIF || - dev->chip_id == CHIP_RV1126_CIF || - dev->chip_id == CHIP_RK3568_CIF)) { + (dev->chip_id == CHIP_RK1808_CIF)) { source_entity = &linked_sensor.sd->entity; sink_entity = &dev->stream[RKCIF_STREAM_CIF].vnode.vdev.entity; @@ -487,6 +516,23 @@ static int rkcif_create_links(struct rkcif_device *dev) break; } + if ((linked_sensor.mbus.type == V4L2_MBUS_BT656 || + linked_sensor.mbus.type == V4L2_MBUS_PARALLEL) && + (dev->chip_id >= CHIP_RV1126_CIF)) { + source_entity = &linked_sensor.sd->entity; + sink_entity = &dev->stream[pad].vnode.vdev.entity; + + ret = media_create_pad_link(source_entity, + pad, + sink_entity, + 0, + MEDIA_LNK_FL_ENABLED); + if (ret) + dev_err(dev->dev, "failed to create link for %s pad[%d]\n", + linked_sensor.sd->name, pad); + continue; + } + for (id = 0; id < stream_num; id++) { source_entity = &linked_sensor.sd->entity; sink_entity = &dev->stream[id].vnode.vdev.entity; @@ -704,14 +750,19 @@ static int rkcif_register_platform_subdevs(struct rkcif_device *cif_dev) { int stream_num = 0, ret; - if (cif_dev->inf_id == RKCIF_MIPI_LVDS) { - stream_num = RKCIF_MAX_STREAM_MIPI; - ret = rkcif_register_stream_vdevs(cif_dev, stream_num, - true); + if (cif_dev->chip_id < CHIP_RV1126_CIF) { + if (cif_dev->inf_id == RKCIF_MIPI_LVDS) { + stream_num = RKCIF_MAX_STREAM_MIPI; + ret = rkcif_register_stream_vdevs(cif_dev, stream_num, + true); + } else { + stream_num = RKCIF_SINGLE_STREAM; + ret = rkcif_register_stream_vdevs(cif_dev, stream_num, + false); + } } else { - stream_num = RKCIF_SINGLE_STREAM; - ret = rkcif_register_stream_vdevs(cif_dev, stream_num, - false); + stream_num = RKCIF_MAX_STREAM_MIPI; + ret = rkcif_register_stream_vdevs(cif_dev, stream_num, true); } if (ret < 0) { @@ -942,13 +993,21 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int if (cif_dev->chip_id == CHIP_RV1126_CIF_LITE) cif_dev->isr_hdl = rkcif_irq_lite_handler; - if (cif_dev->inf_id == RKCIF_MIPI_LVDS) { + 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); + rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID1); + rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID2); + rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID3); + } else { + rkcif_stream_init(cif_dev, RKCIF_STREAM_CIF); + } + } else { + /* for rv1126/rk356x, bt656/bt1120/mipi are multi channels */ rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID0); rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID1); rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID2); rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID3); - } else { - rkcif_stream_init(cif_dev, RKCIF_STREAM_CIF); } #if defined(CONFIG_ROCKCHIP_CIF_WORKMODE_PINGPONG) @@ -1007,16 +1066,22 @@ int rkcif_plat_uninit(struct rkcif_device *cif_dev) if (cif_dev->active_sensor->mbus.type == V4L2_MBUS_CCP2) rkcif_unregister_lvds_subdev(cif_dev); + if (cif_dev->active_sensor->mbus.type == V4L2_MBUS_BT656 || cif_dev->active_sensor->mbus.type == V4L2_MBUS_PARALLEL) rkcif_unregister_dvp_sof_subdev(cif_dev); media_device_unregister(&cif_dev->media_dev); v4l2_device_unregister(&cif_dev->v4l2_dev); - if (cif_dev->inf_id == RKCIF_MIPI_LVDS) + + if (cif_dev->chip_id < CHIP_RV1126_CIF) { + if (cif_dev->inf_id == RKCIF_MIPI_LVDS) + stream_num = RKCIF_MAX_STREAM_MIPI; + else + stream_num = RKCIF_SINGLE_STREAM; + } else { stream_num = RKCIF_MAX_STREAM_MIPI; - else - stream_num = RKCIF_SINGLE_STREAM; + } rkcif_unregister_stream_vdevs(cif_dev, stream_num); return 0; diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index 045282ad485e..11b93c235632 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -39,9 +39,15 @@ #define CIF_MIPI_ID2_VDEV_NAME CIF_VIDEODEVICE_NAME "_mipi_id2" #define CIF_MIPI_ID3_VDEV_NAME CIF_VIDEODEVICE_NAME "_mipi_id3" +#define CIF_DVP_ID0_VDEV_NAME CIF_VIDEODEVICE_NAME "_dvp_id0" +#define CIF_DVP_ID1_VDEV_NAME CIF_VIDEODEVICE_NAME "_dvp_id1" +#define CIF_DVP_ID2_VDEV_NAME CIF_VIDEODEVICE_NAME "_dvp_id2" +#define CIF_DVP_ID3_VDEV_NAME CIF_VIDEODEVICE_NAME "_dvp_id3" + /* - * Rk1808 support 5 channel inputs simultaneously: - * dvp + 4 mipi virtual channels + * RK1808 support 5 channel inputs simultaneously: + * dvp + 4 mipi virtual channels; + * RV1126/RK356X support 4 channels of BT.656/BT.1120/MIPI */ #define RKCIF_MULTI_STREAMS_NUM 5 #define RKCIF_STREAM_MIPI_ID0 0 @@ -50,6 +56,7 @@ #define RKCIF_STREAM_MIPI_ID3 3 #define RKCIF_MAX_STREAM_MIPI 4 #define RKCIF_MAX_STREAM_LVDS 4 +#define RKCIF_MAX_STREAM_DVP 4 #define RKCIF_STREAM_DVP 4 #define RKCIF_MAX_SENSOR 2 @@ -405,6 +412,7 @@ struct rkcif_stream { struct v4l2_rect crop[CROP_SRC_MAX]; struct rkcif_fps_stats fps_stats; struct rkcif_extend_info extend_line; + bool is_dvp_yuv_addr_init; }; struct rkcif_lvds_subdev { @@ -548,5 +556,6 @@ int rkcif_reset_notifier(struct notifier_block *nb, unsigned long action, void * void rkcif_reset_watchdog_timer_handler(struct timer_list *t); void rkcif_config_dvp_clk_sampling_edge(struct rkcif_device *dev, enum rkcif_clk_edge edge); +void rkcif_enable_dvp_clk_dual_edge(struct rkcif_device *dev, bool on); #endif diff --git a/drivers/media/platform/rockchip/cif/hw.c b/drivers/media/platform/rockchip/cif/hw.c index cffdb7e45a1e..688ff60779c3 100644 --- a/drivers/media/platform/rockchip/cif/hw.c +++ b/drivers/media/platform/rockchip/cif/hw.c @@ -326,6 +326,18 @@ static const struct cif_reg rv1126_cif_regs[] = { [CIF_REG_DVP_CUR_DST] = CIF_REG(RV1126_CIF_CUR_DST), [CIF_REG_DVP_LAST_LINE] = CIF_REG(RV1126_CIF_LAST_LINE), [CIF_REG_DVP_LAST_PIX] = CIF_REG(RV1126_CIF_LAST_PIX), + [CIF_REG_DVP_FRM0_ADDR_Y_ID1] = CIF_REG(CIF_FRM0_ADDR_Y_ID1), + [CIF_REG_DVP_FRM0_ADDR_UV_ID1] = CIF_REG(CIF_FRM0_ADDR_UV_ID1), + [CIF_REG_DVP_FRM1_ADDR_Y_ID1] = CIF_REG(CIF_FRM1_ADDR_Y_ID1), + [CIF_REG_DVP_FRM1_ADDR_UV_ID1] = CIF_REG(CIF_FRM1_ADDR_UV_ID1), + [CIF_REG_DVP_FRM0_ADDR_Y_ID2] = CIF_REG(CIF_FRM0_ADDR_Y_ID2), + [CIF_REG_DVP_FRM0_ADDR_UV_ID2] = CIF_REG(CIF_FRM0_ADDR_UV_ID2), + [CIF_REG_DVP_FRM1_ADDR_Y_ID2] = CIF_REG(CIF_FRM1_ADDR_Y_ID2), + [CIF_REG_DVP_FRM1_ADDR_UV_ID2] = CIF_REG(CIF_FRM1_ADDR_UV_ID2), + [CIF_REG_DVP_FRM0_ADDR_Y_ID3] = CIF_REG(CIF_FRM0_ADDR_Y_ID3), + [CIF_REG_DVP_FRM0_ADDR_UV_ID3] = CIF_REG(CIF_FRM0_ADDR_UV_ID3), + [CIF_REG_DVP_FRM1_ADDR_Y_ID3] = CIF_REG(CIF_FRM1_ADDR_Y_ID3), + [CIF_REG_DVP_FRM1_ADDR_UV_ID3] = CIF_REG(CIF_FRM1_ADDR_UV_ID3), [CIF_REG_MIPI_LVDS_ID0_CTRL0] = CIF_REG(CIF_CSI_ID0_CTRL0), [CIF_REG_MIPI_LVDS_ID0_CTRL1] = CIF_REG(CIF_CSI_ID0_CTRL1), [CIF_REG_MIPI_LVDS_ID1_CTRL0] = CIF_REG(CIF_CSI_ID1_CTRL0), diff --git a/drivers/media/platform/rockchip/cif/regs.h b/drivers/media/platform/rockchip/cif/regs.h index 28f6f4240735..65c6042330f7 100644 --- a/drivers/media/platform/rockchip/cif/regs.h +++ b/drivers/media/platform/rockchip/cif/regs.h @@ -148,6 +148,7 @@ enum cif_reg_index { CIF_REG_MMU_AUTO_GATING, /* reg belowed is in grf */ CIF_REG_GRF_CIFIO_CON, + CIF_REG_GRF_CIFIO_CON1, CIF_REG_INDEX_MAX }; @@ -314,6 +315,9 @@ enum cif_reg_index { #define PRE_INF_FRAME_END_EN (0x1 << 8) #define PST_INF_FRAME_END_EN (0x1 << 9) #define LINE_INT_EN (0x1 << 10) +#define DVP_CHANNEL1_FRM_END_EN (0x1 << 11) +#define DVP_CHANNEL2_FRM_END_EN (0x1 << 12) +#define DVP_CHANNEL3_FRM_END_EN (0x1 << 13) /* CIF INTSTAT */ #define INTSTAT_CLS (0x3FF) @@ -332,6 +336,39 @@ enum cif_reg_index { #define INTSTAT_ERR (0xFC) #define DVP_ALL_OVERFLOW (IFIFO_OVERFLOW | DFIFO_OVERFLOW) +#define DVP_DMA_END_INTEN(id) \ + ({ \ + unsigned int mask; \ + switch (id) { \ + case 0: \ + mask = 0x1 << 0; \ + break; \ + default: \ + mask = 0x1 << (id + 10); \ + break; \ + } \ + mask; \ + }) + +#define DVP_LINE_INTEN (0x01 << 10) + +#define DVP_DMA_END_INTSTAT(id) \ + ({ \ + unsigned int mask; \ + switch (id) { \ + case 0: \ + mask = 0x1 << 0; \ + break; \ + default: \ + mask = 0x1 << (id + 10); \ + break; \ + } \ + mask; \ + }) + +#define DVP_PST_INTSTAT PST_INF_FRAME_END +#define DVP_LINE_INTSTAT (0x01 << 10) + /* FRAME STATUS */ #define FRAME_STAT_CLS 0x00 /* write 0 to clear frame 0 */ @@ -390,6 +427,10 @@ enum cif_reg_index { #define BT656_1120_MULTI_ID_MODE_1 (0x00 << 30) #define BT656_1120_MULTI_ID_MODE_2 (0x01 << 30) #define BT656_1120_MULTI_ID_MODE_4 (0x02 << 30) +#define BT656_1120_MULTI_ID_0_MASK ~(0x03 << 4) +#define BT656_1120_MULTI_ID_1_MASK ~(0x03 << 12) +#define BT656_1120_MULTI_ID_2_MASK ~(0x03 << 20) +#define BT656_1120_MULTI_ID_3_MASK ~(0x03 << 28) /* CIF_SCL_CTRL */ #define ENABLE_SCL_DOWN (0x01 << 0) @@ -403,9 +444,52 @@ enum cif_reg_index { #define ENABLE_32BIT_BYPASS (0x01 << 6) #define DISABLE_32BIT_BYPASS (0x00 << 6) -/* CIF_INTSTAT */ +/* CIF_FRAME_INTSTAT */ #define CIF_F0_READY (0x01 << 0) #define CIF_F1_READY (0x01 << 1) +#define DVP_CHANNEL0_FRM_READ (CIF_F0_READY | CIF_F1_READY) +#define DVP_CHANNEL1_F0_READY (0x01 << 4) +#define DVP_CHANNEL1_F1_READY (0x01 << 5) +#define DVP_CHANNEL1_FRM_READ (DVP_CHANNEL1_F0_READY | DVP_CHANNEL1_F1_READY) +#define DVP_CHANNEL2_F0_READY (0x01 << 8) +#define DVP_CHANNEL2_F1_READY (0x01 << 9) +#define DVP_CHANNEL2_FRM_READ (DVP_CHANNEL2_F0_READY | DVP_CHANNEL2_F1_READY) +#define DVP_CHANNEL3_F0_READY (0x01 << 12) +#define DVP_CHANNEL3_F1_READY (0x01 << 13) +#define DVP_CHANNEL3_FRM_READ (DVP_CHANNEL3_F0_READY | DVP_CHANNEL3_F1_READY) + +#define DVP_FRAME_END_ID0 (0x1 << 0) +#define DVP_FRAME_END_ID1 (0x1 << 11) +#define DVP_FRAME_END_ID2 (0x1 << 12) +#define DVP_FRAME_END_ID3 (0x1 << 13) + +#define DVP_FRM_STS_ID0(x) (((x) & (0x3 << 0)) >> 0) +#define DVP_FRM_STS_ID1(x) (((x) & (0x3 << 4)) >> 4) +#define DVP_FRM_STS_ID2(x) (((x) & (0x3 << 8)) >> 8) +#define DVP_FRM_STS_ID3(x) (((x) & (0x3 << 12)) >> 12) + +#define DVP_SW_MULTI_ID(channel, id, bits) \ + ({ \ + unsigned int mask; \ + switch (channel) { \ + case 0: \ + mask = ((bits) << 4) | ((id) << 0); \ + break; \ + case 1: \ + mask = ((bits) << 12) | ((id) << 8); \ + break; \ + case 2: \ + mask = ((bits) << 20) | ((id) << 16); \ + break; \ + case 3: \ + mask = ((bits) << 28) | ((id) << 24); \ + break; \ + default: \ + mask = ((bits) << 4) | ((id) << 0); \ + break; \ + } \ + mask; \ + }) /* CIF CROP */ #define CIF_CROP_Y_SHIFT 16 @@ -594,9 +678,12 @@ enum cif_reg_index { #define CIF_PCLK_DELAY_DISABLE (0x02000000) #define CIF_SAMPLING_EDGE_DOUBLE (0x01000100) #define CIF_SAMPLING_EDGE_SINGLE (0x01000000) -#define CIF_PCLK_DELAY_NUM(num) (0x00ff0000 | ((num) & 0xff)) +#define CIF_PCLK_DELAY_NUM(num) (0x00ff0000 | ((num) & 0xff)) #define CIF_GRF_VI_CON0 (0x340) +#define CIF_GRF_VI_CON1 (0x344) #define RK3568_CIF_PCLK_SAMPLING_EDGE_RISING (0x10000000) #define RK3568_CIF_PCLK_SAMPLING_EDGE_FALLING (0x10001000) +#define RK3568_CIF_PCLK_SINGLE_EDGE (0x02000000) +#define RK3568_CIF_PCLK_DUAL_EDGE (0x02000200) #endif diff --git a/drivers/media/platform/rockchip/cif/version.h b/drivers/media/platform/rockchip/cif/version.h index 10e34d363367..67b6cfc19715 100644 --- a/drivers/media/platform/rockchip/cif/version.h +++ b/drivers/media/platform/rockchip/cif/version.h @@ -57,6 +57,8 @@ *5. modify reset mechanism drivered by real-time frame rate *6. support rk356x iommu uses vb2 sg type *7. register cif sd itf when pipeline completed + *v0.1.10 + *1. rv1126/rk356x support bt656/bt1120 multi channels function */ #define RKCIF_DRIVER_VERSION RKCIF_API_VERSION diff --git a/include/uapi/linux/rk-camera-module.h b/include/uapi/linux/rk-camera-module.h index c714058808cb..1ba1c78838e7 100644 --- a/include/uapi/linux/rk-camera-module.h +++ b/include/uapi/linux/rk-camera-module.h @@ -25,6 +25,25 @@ #define RKMODULE_CAMERA_MODULE_NAME "rockchip,camera-module-name" #define RKMODULE_CAMERA_LENS_NAME "rockchip,camera-module-lens-name" +/* BT.656 & BT.1120 multi channel + * On which channels it can send video data + * related with struct rkmodule_bt656_mbus_info + */ +#define RKMODULE_CAMERA_BT656_ID_EN_BITS_1 (0x1) +#define RKMODULE_CAMERA_BT656_ID_EN_BITS_2 (0x3) +#define RKMODULE_CAMERA_BT656_ID_EN_BITS_3 (0x7) +#define RKMODULE_CAMERA_BT656_ID_EN_BITS_4 (0xf) +#define RKMODULE_CAMERA_BT656_PARSE_ID_LSB BIT(0) +#define RKMODULE_CAMERA_BT656_PARSE_ID_MSB BIT(1) +#define RKMODULE_CAMERA_BT656_CHANNEL_0 BIT(2) +#define RKMODULE_CAMERA_BT656_CHANNEL_1 BIT(3) +#define RKMODULE_CAMERA_BT656_CHANNEL_2 BIT(4) +#define RKMODULE_CAMERA_BT656_CHANNEL_3 BIT(5) +#define RKMODULE_CAMERA_BT656_CHANNELS (RKMODULE_CAMERA_BT656_CHANNEL_0 | \ + RKMODULE_CAMERA_BT656_CHANNEL_1 | \ + RKMODULE_CAMERA_BT656_CHANNEL_2 | \ + RKMODULE_CAMERA_BT656_CHANNEL_3) + #define RKMODULE_GET_MODULE_INFO \ _IOR('V', BASE_VIDIOC_PRIVATE + 0, struct rkmodule_inf) @@ -76,6 +95,8 @@ #define RKMODULE_SET_VICAP_RST_INFO \ _IOR('V', BASE_VIDIOC_PRIVATE + 16, struct rkmodule_vicap_reset_info) +#define RKMODULE_GET_BT656_MBUS_INFO \ + _IOR('V', BASE_VIDIOC_PRIVATE + 17, struct rkmodule_bt656_mbus_info) /** * struct rkmodule_base_inf - module base information * @@ -394,4 +415,10 @@ struct rkmodule_vicap_reset_info { enum rkmodule_reset_src src; } __attribute__ ((packed)); +struct rkmodule_bt656_mbus_info { + __u32 flags; + __u32 id_en_bits; +} __attribute__ ((packed)); + + #endif /* _UAPI_RKMODULE_CAMERA_H */ diff --git a/include/uapi/linux/rkcif-config.h b/include/uapi/linux/rkcif-config.h index 397fd4ba8a31..9e05f3abf273 100644 --- a/include/uapi/linux/rkcif-config.h +++ b/include/uapi/linux/rkcif-config.h @@ -9,7 +9,7 @@ #include #include -#define RKCIF_API_VERSION KERNEL_VERSION(0, 1, 0x9) +#define RKCIF_API_VERSION KERNEL_VERSION(0, 1, 0xa) #define V4L2_CID_CIF_DATA_COMPACT (V4L2_CID_PRIVATE_BASE + 0)