diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 4cd1b0505e49..db4d400a45c2 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -1018,9 +1018,8 @@ cif_input_fmt *rkcif_get_input_fmt(struct rkcif_device *dev, struct v4l2_rect *r } } csi_info->capture_info = capture_info; - } else { - csi_info->capture_info.mode = RKMODULE_CAPTURE_MODE_NONE; } + for (i = 0; i < ARRAY_SIZE(in_fmts); i++) if (fmt.format.code == in_fmts[i].mbus_code && fmt.format.field == in_fmts[i].field) @@ -2502,6 +2501,7 @@ static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream, unsigned long flags; struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf; struct csi_channel_info *channel = &dev->channels[channel_id]; + struct rkcif_stream *buf_stream = stream; stream->lack_buf_cnt = 0; if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || @@ -2521,13 +2521,14 @@ static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream, 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, + if (!list_empty(&buf_stream->buf_head)) { + stream->curr_buf = list_first_entry(&buf_stream->buf_head, struct rkcif_buffer, queue); v4l2_dbg(4, rkcif_debug, &dev->v4l2_dev, "%s %d, stream[%d] buf idx %d\n", __func__, __LINE__, stream->id, stream->curr_buf->vb.vb2_buf.index); list_del(&stream->curr_buf->queue); + atomic_inc(&buf_stream->sub_stream_buf_cnt); } } @@ -2591,13 +2592,17 @@ static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream, } } } else { + if (channel->capture_info.mode == RKMODULE_ONE_CH_TO_MULTI_ISP && + channel->capture_info.one_to_multi.frame_pattern[0] == 1) + buf_stream = &dev->stream[dev->sditf[1]->connect_id]; if (!stream->next_buf) { - if (!list_empty(&stream->buf_head)) { - stream->next_buf = list_first_entry(&stream->buf_head, + if (!list_empty(&buf_stream->buf_head)) { + stream->next_buf = list_first_entry(&buf_stream->buf_head, struct rkcif_buffer, queue); v4l2_dbg(4, rkcif_debug, &dev->v4l2_dev, "%s %d, stream[%d] buf idx %d\n", __func__, __LINE__, stream->id, stream->next_buf->vb.vb2_buf.index); list_del(&stream->next_buf->queue); + atomic_inc(&buf_stream->sub_stream_buf_cnt); } else if (stream->curr_buf) { stream->next_buf = stream->curr_buf; } @@ -2673,6 +2678,38 @@ static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream, stream->buf_owner = RKCIF_DMAEN_BY_VICAP; } +static struct rkcif_stream *rkcif_get_update_buffer_stream(struct rkcif_stream *stream) +{ + struct rkcif_device *dev = stream->cifdev; + struct rkcif_stream *buf_stream = NULL; + u32 i = 0, pattern_cnt = 0, tmp = 0; + + for (i = 0; i < dev->channels[0].capture_info.one_to_multi.isp_num; i++) + pattern_cnt += dev->channels[0].capture_info.one_to_multi.frame_pattern[i]; + + if (pattern_cnt == 0) { + v4l2_info(&dev->v4l2_dev, + "stream[%d] pattern_cnt is %d, pls check it\n", + stream->id, pattern_cnt); + return NULL; + } + tmp = (stream->frame_idx + 1) % pattern_cnt; + pattern_cnt = 0; + for (i = 0; i < dev->channels[0].capture_info.one_to_multi.isp_num; i++) { + pattern_cnt += dev->channels[0].capture_info.one_to_multi.frame_pattern[i]; + if (tmp < pattern_cnt) { + buf_stream = &dev->stream[i]; + break; + } + } + if (buf_stream == NULL) + buf_stream = stream; + if (dev->exp_dbg) + v4l2_info(&dev->v4l2_dev, + "stream[%d] update buffer\n", buf_stream->id); + return buf_stream; +} + static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, int channel_id) { @@ -2684,8 +2721,9 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, struct csi_channel_info *channel = &dev->channels[channel_id]; struct rkisp_rx_buf *dbufs = NULL; struct dma_buf *dbuf = NULL; + struct rkcif_stream *buf_stream = stream; int ret = 0; - u32 buff_addr_y, buff_addr_cbcr; + u32 buff_addr_y = 0, buff_addr_cbcr = 0; unsigned long flags; if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || @@ -2711,8 +2749,18 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, goto stop_dma; } + if (dev->channels[0].capture_info.mode == RKMODULE_ONE_CH_TO_MULTI_ISP) + buf_stream = rkcif_get_update_buffer_stream(stream); + spin_lock_irqsave(&stream->vbq_lock, flags); - if (!list_empty(&stream->buf_head)) { + if (dev->channels[0].capture_info.mode == RKMODULE_ONE_CH_TO_MULTI_ISP && + (buf_stream->state != RKCIF_STATE_STREAMING || buf_stream->stopping)) { + buffer = NULL; + if (stream->frame_phase == CIF_CSI_FRAME0_READY) + stream->curr_buf = NULL; + else + stream->next_buf = NULL; + } else if (!list_empty(&buf_stream->buf_head)) { if (!dummy_buf->vaddr && stream->curr_buf == stream->next_buf && @@ -2722,7 +2770,7 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, if (stream->frame_phase == CIF_CSI_FRAME0_READY) { if (!stream->curr_buf) ret = -EINVAL; - stream->curr_buf = list_first_entry(&stream->buf_head, + stream->curr_buf = list_first_entry(&buf_stream->buf_head, struct rkcif_buffer, queue); if (stream->curr_buf) { list_del(&stream->curr_buf->queue); @@ -2743,7 +2791,7 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, } } else { - stream->next_buf = list_first_entry(&stream->buf_head, + stream->next_buf = list_first_entry(&buf_stream->buf_head, struct rkcif_buffer, queue); if (stream->next_buf) { list_del(&stream->next_buf->queue); @@ -2789,6 +2837,30 @@ 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->dma_en & RKCIF_DMAEN_BY_ISP) { + if (stream->buf_replace_cnt < 2) + stream->buf_replace_cnt++; + if (stream->frame_phase == CIF_CSI_FRAME0_READY && + stream->next_buf) + dbuf = stream->next_buf->dbuf; + else if (stream->frame_phase == CIF_CSI_FRAME1_READY && + stream->curr_buf) + dbuf = stream->curr_buf->dbuf; + + if (dbuf) { + list_for_each_entry(dbufs, &stream->rx_buf_head_vicap, list) { + if (dbufs->dbuf == dbuf) + break; + } + } + if (dbufs) + rkcif_s_rx_buffer(stream, dbufs); + } + } else if (dummy_buf) { + buff_addr_y = dummy_buf->dma_addr; + buff_addr_cbcr = dummy_buf->dma_addr; + } + if (buff_addr_y) { 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) { @@ -2819,25 +2891,6 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, rkcif_write_register(dev, frm_addr_uv, buff_addr_cbcr); } } - if (stream->dma_en & RKCIF_DMAEN_BY_ISP) { - if (stream->buf_replace_cnt < 2) - stream->buf_replace_cnt++; - if (stream->frame_phase == CIF_CSI_FRAME0_READY && - stream->next_buf) - dbuf = stream->next_buf->dbuf; - else if (stream->frame_phase == CIF_CSI_FRAME1_READY && - stream->curr_buf) - dbuf = stream->curr_buf->dbuf; - - if (dbuf) { - list_for_each_entry(dbufs, &stream->rx_buf_head_vicap, list) { - if (dbufs->dbuf == dbuf) - break; - } - } - if (dbufs) - rkcif_s_rx_buffer(stream, dbufs); - } } spin_unlock_irqrestore(&stream->vbq_lock, flags); return ret; @@ -4476,6 +4529,8 @@ static int rkcif_csi_stream_start(struct rkcif_stream *stream, unsigned int mode struct rkcif_sensor_info *active_sensor = dev->active_sensor; enum v4l2_mbus_type mbus_type = active_sensor->mbus.type; struct csi_channel_info *channel; + int isp_num = dev->channels[0].capture_info.one_to_multi.isp_num; + struct rkcif_pipeline *p = &dev->pipe; u32 ret = 0; int i; @@ -4503,6 +4558,14 @@ static int rkcif_csi_stream_start(struct rkcif_stream *stream, unsigned int mode } } rkcif_csi_channel_init(stream, channel); + + if (dev->channels[0].capture_info.mode == RKMODULE_ONE_CH_TO_MULTI_ISP) { + if (atomic_read(&p->stream_cnt) < isp_num - 1) + goto one_to_multi_skip; + else + *channel = dev->channels[0]; + } + if (stream->state != RKCIF_STATE_STREAMING) { if (mode == RKCIF_STREAM_MODE_CAPTURE) { stream->dma_en |= RKCIF_DMAEN_BY_VICAP; @@ -4549,6 +4612,7 @@ static int rkcif_csi_stream_start(struct rkcif_stream *stream, unsigned int mode } } } +one_to_multi_skip: if (stream->state != RKCIF_STATE_STREAMING) { stream->line_int_cnt = 0; if (stream->is_line_wake_up) @@ -4990,7 +5054,9 @@ void rkcif_buf_queue(struct vb2_buffer *vb) } spin_lock_irqsave(&stream->vbq_lock, flags); list_add_tail(&cifbuf->queue, &stream->buf_head); + cifbuf->id = stream->id; spin_unlock_irqrestore(&stream->vbq_lock, flags); + if (stream->dma_en & RKCIF_DMAEN_BY_ISP && (!cifbuf->dbuf)) { struct rkisp_rx_buf *dbufs = NULL; @@ -5010,12 +5076,14 @@ void rkcif_buf_queue(struct vb2_buffer *vb) } if (stream->cifdev->workmode == RKCIF_WORKMODE_PINGPONG && stream->lack_buf_cnt && - stream->cur_stream_mode & RKCIF_STREAM_MODE_CAPTURE) + stream->cur_stream_mode & RKCIF_STREAM_MODE_CAPTURE && + stream->cifdev->channels[0].capture_info.mode != RKMODULE_ONE_CH_TO_MULTI_ISP) rkcif_check_buffer_update_pingpong(stream, stream->id); - v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev, - "stream[%d] buf queue, index: %d, dma_addr 0x%x\n", - stream->id, vb->index, cifbuf->buff_addr[0]); atomic_inc(&stream->buf_cnt); + v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev, + "stream[%d] buf queue, index: %d, dma_addr 0x%x, dbuf %p, mem_priv %p\n", + stream->id, vb->index, cifbuf->buff_addr[0], cifbuf->vb.vb2_buf.planes[0].dbuf, + cifbuf->vb.vb2_buf.planes[0].mem_priv); } void rkcif_free_rx_buf(struct rkcif_stream *stream, int buf_num) @@ -5466,6 +5534,78 @@ static void rkcif_detach_sync_mode(struct rkcif_device *cif_dev) mutex_unlock(&hw->dev_lock); } +static void rkcif_clean_state_one_to_multi_mode(struct rkcif_device *dev) +{ + struct sditf_priv *priv = NULL; + struct sditf_effect_exp *effect_exp; + struct sditf_effect_time *effect_time; + struct sditf_effect_gain *effect_gain; + struct sditf_time *time; + struct sditf_gain *gain; + int i = 0; + + while (work_busy(&dev->exp_work)) { + usleep_range(2000, 3000); + i++; + if (i > 5) + break; + } + + for (i = 0; i < dev->sditf_cnt; i++) { + priv = dev->sditf[i]; + if (priv) { + atomic_set(&priv->frm_sync_seq, 0); + priv->frame_idx.cur_frame_idx = 0; + priv->frame_idx.total_frame_idx = 0; + while (!list_empty(&priv->effect_exp_head)) { + effect_exp = list_first_entry(&priv->effect_exp_head, + struct sditf_effect_exp, list); + if (effect_exp) { + list_del(&effect_exp->list); + kfree(effect_exp); + effect_exp = NULL; + } + } + while (!list_empty(&priv->time_head)) { + time = list_first_entry(&priv->time_head, + struct sditf_time, list); + if (time) { + list_del(&time->list); + kfree(time); + time = NULL; + } + } + while (!list_empty(&priv->time_head)) { + gain = list_first_entry(&priv->gain_head, + struct sditf_gain, list); + if (gain) { + list_del(&gain->list); + kfree(gain); + gain = NULL; + } + } + } + } + while (!list_empty(&dev->effect_time_head)) { + effect_time = list_first_entry(&dev->effect_time_head, + struct sditf_effect_time, list); + if (effect_time) { + list_del(&effect_time->list); + kfree(effect_time); + effect_time = NULL; + } + } + while (!list_empty(&dev->effect_gain_head)) { + effect_gain = list_first_entry(&dev->effect_gain_head, + struct sditf_effect_gain, list); + if (effect_gain) { + list_del(&effect_gain->list); + kfree(effect_gain); + effect_gain = NULL; + } + } +} + void rkcif_do_stop_stream(struct rkcif_stream *stream, enum rkcif_stream_mode mode) { @@ -5501,8 +5641,10 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream, fs_time = stream->readout.fs_timestamp; spin_unlock_irqrestore(&stream->fps_lock, flags); cur_time = rkcif_time_get_ns(dev); - if (cur_time > fs_time && - cur_time - fs_time < (frame_time_ns - 10000000)) { + if ((cur_time > fs_time && + cur_time - fs_time < (frame_time_ns - 10000000)) || + (dev->channels[0].capture_info.mode == RKMODULE_ONE_CH_TO_MULTI_ISP && + stream->id != 0)) { spin_lock_irqsave(&stream->vbq_lock, flags); if (stream->dma_en & RKCIF_DMAEN_BY_VICAP) stream->to_stop_dma = RKCIF_DMAEN_BY_VICAP; @@ -5554,6 +5696,11 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream, !stream->is_wait_dma_stop, msecs_to_jiffies(1000)); } + + if (!atomic_read(&dev->pipe.stream_cnt) && + dev->channels[0].capture_info.mode == RKMODULE_ONE_CH_TO_MULTI_ISP) + rkcif_clean_state_one_to_multi_mode(dev); + if ((mode & RKCIF_STREAM_MODE_CAPTURE) == RKCIF_STREAM_MODE_CAPTURE) { /* release buffers */ spin_lock_irqsave(&stream->vbq_lock, flags); @@ -5578,6 +5725,14 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream, stream->id, buf->buff_addr[0]); vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); } + while (!list_empty(&stream->buf_head_multi_cache)) { + buf = list_first_entry(&stream->buf_head_multi_cache, + struct rkcif_buffer, queue); + if (buf) { + list_del(&buf->queue); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } + } INIT_LIST_HEAD(&stream->buf_head); while (!list_empty(&stream->vb_done_list)) { buf = list_first_entry(&stream->vb_done_list, @@ -5635,6 +5790,8 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream, dev->wait_line = 0; stream->is_line_wake_up = false; } + if (atomic_read(&dev->pipe.stream_cnt) == 0) + atomic_set(&stream->sub_stream_buf_cnt, 0); if (can_reset && hw_dev->dummy_buf.vaddr) rkcif_destroy_dummy_buf(stream); } @@ -5645,6 +5802,8 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream, if (mode == stream->cur_stream_mode) rkcif_detach_sync_mode(dev); + if (!atomic_read(&dev->pipe.stream_cnt) && dev->is_alloc_buf_user) + rkcif_free_buf_by_user_require(dev); stream->cur_stream_mode &= ~mode; v4l2_info(&dev->v4l2_dev, "stream[%d] stopping finished, dma_en 0x%x\n", stream->id, stream->dma_en); mutex_unlock(&dev->stream_lock); @@ -6715,10 +6874,13 @@ static void rkcif_attach_sync_mode(struct rkcif_device *cifdev) sync_cfg.group = 0; } else { for (j = 0; j < cifdev->sditf_cnt; j++) { - ret |= v4l2_subdev_call(cifdev->sditf[j]->sensor_sd, - core, ioctl, - RKMODULE_GET_SYNC_MODE, - &sync_type); + if (cifdev->sditf[j]->sensor_sd) + ret |= v4l2_subdev_call(cifdev->sditf[j]->sensor_sd, + core, ioctl, + RKMODULE_GET_SYNC_MODE, + &sync_type); + else + ret = -EINVAL; if (!ret && sync_type) break; } @@ -6726,10 +6888,13 @@ static void rkcif_attach_sync_mode(struct rkcif_device *cifdev) sync_cfg.type = sync_type; else sync_cfg.type = NO_SYNC_MODE; - ret = v4l2_subdev_call(cifdev->sditf[j]->sensor_sd, - core, ioctl, - RKMODULE_GET_GROUP_ID, - &sync_group); + if (cifdev->sditf[0]->sensor_sd) + ret = v4l2_subdev_call(cifdev->sditf[0]->sensor_sd, + core, ioctl, + RKMODULE_GET_GROUP_ID, + &sync_group); + else + ret = -EINVAL; if (!ret && sync_group < RKCIF_MAX_GROUP) sync_cfg.group = sync_group; else @@ -6767,10 +6932,13 @@ static void rkcif_attach_sync_mode(struct rkcif_device *cifdev) priv = dev->sditf[0]; if (priv && priv->is_combine_mode && dev->sditf_cnt <= RKCIF_MAX_SDITF) { for (j = 0; j < dev->sditf_cnt; j++) { - ret |= v4l2_subdev_call(dev->sditf[j]->sensor_sd, - core, ioctl, - RKMODULE_GET_SYNC_MODE, - &sync_type); + if (dev->sditf[j]->sensor_sd) + ret |= v4l2_subdev_call(dev->sditf[j]->sensor_sd, + core, ioctl, + RKMODULE_GET_SYNC_MODE, + &sync_type); + else + ret = -EINVAL; if (!ret && sync_type) { priv = dev->sditf[j]; break; @@ -6780,10 +6948,13 @@ static void rkcif_attach_sync_mode(struct rkcif_device *cifdev) sync_cfg.type = sync_type; else sync_cfg.type = NO_SYNC_MODE; - ret = v4l2_subdev_call(priv->sensor_sd, - core, ioctl, - RKMODULE_GET_GROUP_ID, - &sync_group); + if (priv->sensor_sd) + ret = v4l2_subdev_call(priv->sensor_sd, + core, ioctl, + RKMODULE_GET_GROUP_ID, + &sync_group); + else + ret = -EINVAL; if (!ret && sync_group < RKCIF_MAX_GROUP) sync_cfg.group = sync_group; else @@ -7004,9 +7175,15 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, enum rkcif_stream_mode mo } else { ret = rkcif_stream_start(stream, mode); } - if (ret < 0) goto destroy_buf; + if (stream->cur_stream_mode == RKCIF_STREAM_MODE_NONE && + dev->channels[0].capture_info.mode == RKMODULE_ONE_CH_TO_MULTI_ISP && + stream->id == 0) { + for (i = 0; i < dev->sditf_cnt; i++) + sditf_get_default_exp(dev->sditf[i]); + schedule_work(&dev->exp_work); + } if (stream->cur_stream_mode == RKCIF_STREAM_MODE_NONE) { ret = video_device_pipeline_start(&node->vdev, &dev->pipe.pipe); @@ -7311,6 +7488,7 @@ void rkcif_stream_init(struct rkcif_device *dev, u32 id) stream->cifdev = dev; INIT_LIST_HEAD(&stream->buf_head); + INIT_LIST_HEAD(&stream->buf_head_multi_cache); INIT_LIST_HEAD(&stream->rx_buf_head); INIT_LIST_HEAD(&stream->rx_buf_head_vicap); INIT_LIST_HEAD(&stream->rockit_buf_head); @@ -7384,6 +7562,7 @@ void rkcif_stream_init(struct rkcif_device *dev, u32 id) init_completion(&stream->stop_complete); stream->is_wait_stop_complete = false; stream->thunderboot_skip_interval = get_rk_cam_skip_frame_interval(); + atomic_set(&stream->sub_stream_buf_cnt, 0); } static int rkcif_fh_open(struct file *filp) @@ -7987,6 +8166,77 @@ static bool rkcif_check_can_be_online(struct rkcif_device *cif_dev) return true; } +static void rkcif_alloc_buf_by_user_require(struct rkcif_device *dev, + struct rkcif_buffer_info *buf_info) +{ + struct rkcif_stream *detect_stream = &dev->stream[0]; + struct v4l2_pix_format_mplane *pixm = &detect_stream->pixm; + struct rkcif_extend_info *extend_line = &detect_stream->extend_line; + const struct v4l2_plane_pix_format *plane_fmt; + int ret = 0; + int i = 0; + int height = 0; + int h = 0; + u32 size = 0; + bool is_extended = false; + + is_extended = rkcif_is_extending_line_for_height(dev, + detect_stream, + detect_stream->cif_fmt_in); + if (detect_stream->crop_enable) + height = detect_stream->crop[CROP_SRC_ACT].height; + else + height = pixm->height; + if (is_extended && extend_line->is_extended) { + height = extend_line->pixm.height; + pixm = &extend_line->pixm; + } + h = round_up(height, MEMORY_ALIGN_ROUND_UP_HEIGHT); + plane_fmt = &pixm->plane_fmt[0]; + size = plane_fmt->sizeimage / height * h; + + for (i = 0; i < buf_info->buf_num; i++) { + if (!dev->buf_user[i]) { + dev->buf_user[i] = kzalloc(sizeof(*dev->buf_user[i]), GFP_KERNEL); + if (!dev->buf_user[i]) { + buf_info->buf_num = i; + break; + } + } + dev->buf_user[i]->is_need_dbuf = true; + dev->buf_user[i]->is_need_dmafd = true; + dev->buf_user[i]->is_need_vaddr = true; + dev->buf_user[i]->size = size; + ret = rkcif_alloc_buffer(dev, dev->buf_user[i]); + if (ret) { + buf_info->buf_num = i; + kfree(dev->buf_user[i]); + dev->buf_user[i] = NULL; + break; + } + buf_info->dma_fd[i] = dev->buf_user[i]->dma_fd; + } + if (buf_info->buf_num > 0) + dev->is_alloc_buf_user = true; +} + +void rkcif_free_buf_by_user_require(struct rkcif_device *dev) +{ + int i = 0; + + while (i < VB2_MAX_FRAME) { + if (dev->buf_user[i]) { + rkcif_free_buffer(dev, dev->buf_user[i]); + kfree(dev->buf_user[i]); + dev->buf_user[i] = NULL; + } else { + break; + } + i++; + } + dev->is_alloc_buf_user = false; +} + static int rkcif_do_reset_work(struct rkcif_device *cif_dev, enum rkmodule_reset_src reset_src); static long rkcif_ioctl_default(struct file *file, void *fh, @@ -7998,11 +8248,13 @@ static long rkcif_ioctl_default(struct file *file, void *fh, struct v4l2_rect rect; struct csi_channel_info csi_info; struct rkcif_fps fps; + struct rkcif_buffer_info *buf_info = NULL; + struct rkmodule_capture_info *capture_info; int reset_src; struct rkcif_quick_stream_param *stream_param; bool is_single_dev = false; struct v4l2_subdev *sd; - int ret = -EINVAL; + int ret = 0; int i = 0; int stream_num = 0; bool is_can_be_online = false; @@ -8176,11 +8428,48 @@ static long rkcif_ioctl_default(struct file *file, void *fh, v4l2_subdev_call(dev->terminal_sensor.sd, core, ioctl, RKMODULE_SET_QUICK_STREAM, &on); break; + case RKCIF_CMD_ALLOC_BUF: + buf_info = (struct rkcif_buffer_info *)arg; + if (buf_info == NULL) + return -ENOMEM; + if (buf_info->buf_num > VIDEO_MAX_FRAME) { + v4l2_err(&dev->v4l2_dev, "alloc buf fail, max buf num %d\n", + VIDEO_MAX_FRAME); + return -EINVAL; + } + mutex_lock(&dev->stream_lock); + if (dev->is_alloc_buf_user) { + v4l2_err(&dev->v4l2_dev, "it's already alloc buf, release buf before alloc new buf\n"); + mutex_unlock(&dev->stream_lock); + return -EINVAL; + } + rkcif_alloc_buf_by_user_require(dev, buf_info); + mutex_unlock(&dev->stream_lock); + break; + case RKCIF_CMD_FREE_BUF: + mutex_lock(&dev->stream_lock); + if (dev->is_alloc_buf_user) + rkcif_free_buf_by_user_require(dev); + mutex_unlock(&dev->stream_lock); + break; + case RKMODULE_SET_CAPTURE_MODE: + capture_info = (struct rkmodule_capture_info *)arg; + if (capture_info->mode == RKMODULE_ONE_CH_TO_MULTI_ISP) { + for (i = 0; i < capture_info->one_to_multi.isp_num; i++) { + if (capture_info->one_to_multi.frame_pattern[i] == 0 || + capture_info->one_to_multi.frame_pattern[i] > 32) + return -EINVAL; + } + } + dev->channels[0].capture_info = *capture_info; + v4l2_info(&dev->v4l2_dev, + "set capture mode %d\n", dev->channels[0].capture_info.mode); + break; default: return -EINVAL; } - return 0; + return ret; } static const struct v4l2_ioctl_ops rkcif_v4l2_ioctl_ops = { @@ -8225,6 +8514,16 @@ void rkcif_vb_done_oneframe(struct rkcif_stream *stream, atomic_dec(&stream->buf_cnt); } +static void rkcif_vb_done_one_to_multi(struct rkcif_device *dev, + struct rkcif_buffer *active_buf) +{ + struct rkcif_stream *stream = &dev->stream[active_buf->id]; + struct sditf_priv *priv = dev->sditf[stream->id]; + + active_buf->vb.sequence = priv->frame_idx.cur_frame_idx - 1; + rkcif_vb_done_oneframe(stream, &active_buf->vb); +} + static void rkcif_tasklet_handle(unsigned long data) { struct rkcif_stream *stream = (struct rkcif_stream *)data; @@ -8240,7 +8539,11 @@ static void rkcif_tasklet_handle(unsigned long data) buf = list_first_entry(&local_list, struct rkcif_buffer, queue); list_del(&buf->queue); - rkcif_vb_done_oneframe(stream, &buf->vb); + atomic_dec(&stream->cifdev->stream[buf->id].sub_stream_buf_cnt); + if (stream->cifdev->channels[0].capture_info.mode == RKMODULE_ONE_CH_TO_MULTI_ISP) + rkcif_vb_done_one_to_multi(stream->cifdev, buf); + else + rkcif_vb_done_oneframe(stream, &buf->vb); } } @@ -9498,6 +9801,8 @@ static void rkcif_buf_done_prepare(struct rkcif_stream *stream, rkcif_buf_queue(&active_buf->vb.vb2_buf); return; } + if (cif_dev->channels[0].capture_info.mode == RKMODULE_ONE_CH_TO_MULTI_ISP) + vb_done->sequence /= cif_dev->channels[0].capture_info.one_to_multi.isp_num; } else if (cif_dev->rdbk_buf[stream->id]) { vb_done = &cif_dev->rdbk_buf[stream->id]->vb; if (cif_dev->chip_id < CHIP_RK3588_CIF && @@ -11373,7 +11678,10 @@ static void rkcif_deal_sof(struct rkcif_device *cif_dev) if (!detect_stream->thunderboot_skip_interval || (detect_stream->thunderboot_skip_interval && (detect_stream->frame_idx % detect_stream->thunderboot_skip_interval) == 0)) { - rkcif_send_sof(cif_dev); + if (cif_dev->channels[0].capture_info.mode == RKMODULE_ONE_CH_TO_MULTI_ISP) + schedule_work(&cif_dev->exp_work); + else + rkcif_send_sof(cif_dev); if (detect_stream->cifdev->rdbk_debug && detect_stream->frame_idx < 15) v4l2_info(&cif_dev->v4l2_dev, @@ -12130,6 +12438,24 @@ static void rkcif_save_other_intstat_with_combine_mode(struct rkcif_device *cif_ } } +static void rkcif_check_one_to_multi_sub_stream_stop_state(struct rkcif_device *cif_dev) +{ + struct rkcif_stream *stream = NULL; + struct csi_channel_info *channel = &cif_dev->channels[0]; + int i = 0; + + if (channel->capture_info.mode != RKMODULE_ONE_CH_TO_MULTI_ISP) + return; + + for (i = 1; i < channel->capture_info.one_to_multi.isp_num; i++) { + stream = &cif_dev->stream[i]; + if (stream->stopping && atomic_read(&stream->sub_stream_buf_cnt) == 0) { + stream->stopping = false; + wake_up(&stream->wq_stopped); + } + } +} + /* pingpong irq for rk3588 and next */ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) { @@ -12367,6 +12693,7 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) } rkcif_monitor_reset_event(cif_dev); cif_dev->irq_stats.frm_end_cnt[stream->id]++; + rkcif_check_one_to_multi_sub_stream_stop_state(cif_dev); } for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { @@ -12646,6 +12973,7 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev) } } cif_dev->irq_stats.frm_end_cnt[stream->id]++; + rkcif_check_one_to_multi_sub_stream_stop_state(cif_dev); } for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { if (intstat & CSI_START_INTSTAT(i)) { diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index 417f44c9ec2f..d8064a077ea4 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -1457,8 +1457,72 @@ static int rkcif_pipeline_set_stream(struct rkcif_pipeline *p, bool on) struct rkcif_device *cif_dev = container_of(p, struct rkcif_device, pipe); bool can_be_set = false; int i, ret = 0; + u32 isp_num = 0; - if (cif_dev->hdr.hdr_mode == NO_HDR || cif_dev->hdr.hdr_mode == HDR_COMPR) { + if (cif_dev->channels[0].capture_info.mode == RKMODULE_ONE_CH_TO_MULTI_ISP) { + if (!on && atomic_dec_return(&p->stream_cnt) > 0) + return 0; + if (on) { + atomic_inc(&p->stream_cnt); + isp_num = cif_dev->channels[0].capture_info.one_to_multi.isp_num; + if (atomic_read(&p->stream_cnt) == 1) { + rockchip_set_system_status(SYS_STATUS_CIF0); + can_be_set = false; + } else if (atomic_read(&p->stream_cnt) == isp_num) { + can_be_set = true; + } + } + + if ((on && can_be_set) || !on) { + if (on) { + cif_dev->irq_stats.csi_overflow_cnt = 0; + cif_dev->irq_stats.csi_bwidth_lack_cnt = 0; + cif_dev->irq_stats.dvp_bus_err_cnt = 0; + cif_dev->irq_stats.dvp_line_err_cnt = 0; + cif_dev->irq_stats.dvp_overflow_cnt = 0; + cif_dev->irq_stats.dvp_pix_err_cnt = 0; + cif_dev->irq_stats.all_err_cnt = 0; + cif_dev->irq_stats.csi_size_err_cnt = 0; + cif_dev->irq_stats.dvp_size_err_cnt = 0; + cif_dev->irq_stats.dvp_bwidth_lack_cnt = 0; + cif_dev->irq_stats.frm_end_cnt[0] = 0; + cif_dev->irq_stats.frm_end_cnt[1] = 0; + cif_dev->irq_stats.frm_end_cnt[2] = 0; + cif_dev->irq_stats.frm_end_cnt[3] = 0; + cif_dev->irq_stats.not_active_buf_cnt[0] = 0; + cif_dev->irq_stats.not_active_buf_cnt[1] = 0; + cif_dev->irq_stats.not_active_buf_cnt[2] = 0; + cif_dev->irq_stats.not_active_buf_cnt[3] = 0; + cif_dev->irq_stats.trig_simult_cnt[0] = 0; + cif_dev->irq_stats.trig_simult_cnt[1] = 0; + cif_dev->irq_stats.trig_simult_cnt[2] = 0; + cif_dev->irq_stats.trig_simult_cnt[3] = 0; + cif_dev->reset_watchdog_timer.is_triggered = false; + cif_dev->reset_watchdog_timer.is_running = false; + cif_dev->err_state_work.last_timestamp = 0; + cif_dev->is_toisp_reset = false; + for (i = 0; i < cif_dev->num_channels; i++) + cif_dev->reset_watchdog_timer.last_buf_wakeup_cnt[i] = 0; + cif_dev->reset_watchdog_timer.run_cnt = 0; + } + + /* phy -> sensor */ + for (i = 0; i < p->num_subdevs; i++) { + if (p->subdevs[i] == cif_dev->terminal_sensor.sd && + on && + cif_dev->is_thunderboot && + !rk_tb_mcu_is_done()) { + cif_dev->tb_client.data = p->subdevs[i]; + cif_dev->tb_client.cb = rkcif_sensor_streaming_cb; + rk_tb_client_register_cb(&cif_dev->tb_client); + } else { + ret = v4l2_subdev_call(p->subdevs[i], video, s_stream, on); + } + if (on && ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) + goto err_stream_off; + } + } + } else if (cif_dev->hdr.hdr_mode == NO_HDR || cif_dev->hdr.hdr_mode == HDR_COMPR) { if ((on && atomic_inc_return(&p->stream_cnt) > 1) || (!on && atomic_dec_return(&p->stream_cnt) > 0)) return 0; @@ -1824,6 +1888,7 @@ static int _set_pipeline_default_fmt(struct rkcif_device *dev) static int subdev_asyn_register_itf(struct rkcif_device *dev) { struct sditf_priv *sditf = NULL; + int i = 0; int ret = 0; if (IS_ENABLED(CONFIG_NO_GKI)) { @@ -1834,9 +1899,13 @@ static int subdev_asyn_register_itf(struct rkcif_device *dev) return 0; } } - sditf = dev->sditf[0]; - if (sditf && (!sditf->is_combine_mode) && (!dev->is_notifier_isp)) { - ret = v4l2_async_register_subdev_sensor(&sditf->sd); + + if (!dev->is_notifier_isp) { + for (i = 0; i < dev->sditf_cnt; i++) { + sditf = dev->sditf[i]; + if (sditf && (!sditf->is_combine_mode)) + ret = v4l2_async_register_subdev_sensor(&sditf->sd); + } dev->is_notifier_isp = true; } @@ -2264,6 +2333,320 @@ static void rkcif_deal_err_intr(struct work_struct *work) rkcif_write_register_or(cif_dev, CIF_REG_MIPI_LVDS_INTEN, CSI_BANDWIDTH_LACK_V1); } +static void rkcif_exposure_effect_sequeue_match(struct rkcif_device *dev, + struct sditf_effect_time *effect_time, + struct sditf_effect_gain *effect_gain) +{ + struct sditf_effect_time *new_effect_time = NULL; + struct sditf_effect_gain *new_effect_gain = NULL; + + if (effect_time->sequence < effect_gain->sequence) { + if (!list_empty(&dev->effect_time_head)) { + new_effect_time = list_first_entry(&dev->effect_time_head, + struct sditf_effect_time, + list); + if (new_effect_time) { + list_del(&new_effect_time->list); + kfree(effect_time); + effect_time = new_effect_time; + rkcif_exposure_effect_sequeue_match(dev, effect_time, effect_gain); + } else { + return; + } + } else { + return; + } + } else if (effect_time->sequence > effect_gain->sequence) { + if (!list_empty(&dev->effect_gain_head)) { + new_effect_gain = list_first_entry(&dev->effect_gain_head, + struct sditf_effect_gain, + list); + if (new_effect_gain) { + list_del(&new_effect_gain->list); + kfree(effect_gain); + effect_gain = new_effect_gain; + rkcif_exposure_effect_sequeue_match(dev, effect_time, effect_gain); + } else { + return; + } + } else { + return; + } + } +} + +static void rkcif_get_cur_effect_sequeue(struct rkcif_device *dev, + u32 total_sequeue, + u32 *cur_sequeue, + u32 *cur_id) +{ + u32 i = 0, pattern_cnt = 0, tmp = 0; + u32 tmp_pattern_cnt = 0, offset = 0; + + for (i = 0; i < dev->channels[0].capture_info.one_to_multi.isp_num; i++) + pattern_cnt += dev->channels[0].capture_info.one_to_multi.frame_pattern[i]; + + if (pattern_cnt == 0) { + v4l2_err(&dev->v4l2_dev, "pattern_cnt is %d, pls check it\n", pattern_cnt); + return; + } + *cur_sequeue = total_sequeue / pattern_cnt; + tmp = total_sequeue % pattern_cnt; + pattern_cnt = 0; + for (i = 0; i < dev->channels[0].capture_info.one_to_multi.isp_num; i++) { + pattern_cnt += dev->channels[0].capture_info.one_to_multi.frame_pattern[i]; + if (i > 0) + tmp_pattern_cnt += dev->channels[0].capture_info.one_to_multi.frame_pattern[i - 1]; + if (tmp < pattern_cnt) { + *cur_id = i; + offset = tmp - tmp_pattern_cnt; + break; + } + } + *cur_sequeue *= dev->channels[0].capture_info.one_to_multi.frame_pattern[*cur_id]; + *cur_sequeue += offset; +} + +static void rkcif_update_effect_exposure(struct rkcif_device *dev) +{ + struct sditf_priv *priv = NULL; + struct sditf_effect_exp *effect_exp = NULL; + struct sditf_effect_time *effect_time = NULL; + struct sditf_effect_gain *effect_gain = NULL; + u32 cur_sequeue = 0; + u32 cur_id = 0; + + if (!list_empty(&dev->effect_time_head) && (!list_empty(&dev->effect_gain_head))) { + effect_time = list_first_entry(&dev->effect_time_head, + struct sditf_effect_time, + list); + if (effect_time) + list_del(&effect_time->list); + + effect_gain = list_first_entry(&dev->effect_gain_head, + struct sditf_effect_gain, + list); + if (effect_gain) + list_del(&effect_gain->list); + } + + if (effect_time && effect_gain) { + rkcif_exposure_effect_sequeue_match(dev, effect_time, effect_gain); + effect_exp = kzalloc(sizeof(*effect_exp), GFP_KERNEL); + if (effect_exp && effect_time && effect_gain) { + rkcif_get_cur_effect_sequeue(dev, effect_time->sequence, &cur_sequeue, &cur_id); + priv = dev->sditf[cur_id]; + effect_exp->exp.sequence = cur_sequeue; + effect_exp->exp.time = effect_time->time; + effect_exp->exp.gain = effect_gain->gain; + mutex_lock(&priv->mutex); + list_add_tail(&effect_exp->list, &priv->effect_exp_head); + mutex_unlock(&priv->mutex); + sditf_event_exposure_notifier(priv, effect_exp); + } else { + v4l2_err(&dev->v4l2_dev, "Failed to alloc struct sditf_effect_exp\n"); + } + if (effect_time) { + kfree(effect_time); + effect_time = NULL; + } + if (effect_gain) { + kfree(effect_gain); + effect_gain = NULL; + } + } else { + if (effect_time) { + kfree(effect_time); + effect_time = NULL; + } + if (effect_gain) { + kfree(effect_gain); + effect_gain = NULL; + } + v4l2_err(&dev->v4l2_dev, "Failed to get effect time or gain\n"); + } +} + +static int rkcif_get_exp_effect_stream_id(struct rkcif_device *dev, u32 effect_frame) +{ + u32 i = 0, pattern_cnt = 0, tmp = 0; + int id = 0; + + for (i = 0; i < dev->channels[0].capture_info.one_to_multi.isp_num; i++) + pattern_cnt += dev->channels[0].capture_info.one_to_multi.frame_pattern[i]; + + if (pattern_cnt == 0) + return -EINVAL; + tmp = effect_frame % pattern_cnt; + pattern_cnt = 0; + for (i = 0; i < dev->channels[0].capture_info.one_to_multi.isp_num; i++) { + pattern_cnt += dev->channels[0].capture_info.one_to_multi.frame_pattern[i]; + if (tmp < pattern_cnt) { + id = i; + break; + } + } + return id; +} + +static void rkcif_exp_work(struct work_struct *exp_work) +{ + struct rkcif_device *dev = container_of(exp_work, + struct rkcif_device, + exp_work); + struct sditf_priv *priv = NULL; + struct rkcif_stream *stream = &dev->stream[0]; + struct sditf_time *time; + struct sditf_gain *gain; + struct sditf_effect_time *effect_time; + struct sditf_effect_gain *effect_gain; + struct v4l2_ctrl *ctrl; + u32 cur_time = 0; + u32 cur_gain = 0; + int i = 0; + int id = 0; + int min_delay = 0; + int effect_frame = 0; + + id = rkcif_get_exp_effect_stream_id(dev, stream->frame_idx - 1); + if (id < 0) { + dev_err(dev->dev, "%s %d get exp_effect stream failed\n", + __func__, __LINE__); + return; + } + priv = dev->sditf[id]; + if (stream->frame_idx != 0) + sditf_event_inc_sof(priv); + + if (stream->frame_idx == 0) { + cur_time = priv->cur_time; + } else { + effect_frame = stream->frame_idx + dev->exp_delay.time_delay - 1; + id = rkcif_get_exp_effect_stream_id(dev, effect_frame); + if (id < 0) { + dev_err(dev->dev, "%s %d get exp_effect stream failed\n", + __func__, __LINE__); + return; + } + priv = dev->sditf[id]; + if (!list_empty(&priv->time_head)) { + time = list_first_entry(&priv->time_head, + struct sditf_time, + list); + if (time) { + mutex_lock(&priv->mutex); + list_del(&time->list); + mutex_unlock(&priv->mutex); + cur_time = time->time; + kfree(time); + } + } else { + cur_time = priv->cur_time; + } + if (dev->exp_dbg) + dev_info(priv->dev, "exp set id %d, val 0x%x\n", + priv->connect_id, cur_time); + } + ctrl = v4l2_ctrl_find(dev->terminal_sensor.sd->ctrl_handler, + V4L2_CID_EXPOSURE); + v4l2_ctrl_s_ctrl(ctrl, cur_time); + priv->cur_time = cur_time; + if (stream->frame_idx == 0) { + cur_gain = priv->cur_gain; + } else { + effect_frame = stream->frame_idx + dev->exp_delay.gain_delay - 1; + id = rkcif_get_exp_effect_stream_id(dev, effect_frame); + if (id < 0) { + dev_err(dev->dev, "%s %d get exp_effect stream failed\n", + __func__, __LINE__); + return; + } + priv = dev->sditf[id]; + if (!list_empty(&priv->gain_head)) { + gain = list_first_entry(&priv->gain_head, + struct sditf_gain, + list); + if (gain) { + mutex_lock(&priv->mutex); + list_del(&gain->list); + mutex_unlock(&priv->mutex); + cur_gain = gain->gain; + kfree(gain); + } + } else { + cur_gain = priv->cur_gain; + } + if (dev->exp_dbg) + dev_info(priv->dev, "gain set id %d, val 0x%x\n", + priv->connect_id, cur_gain); + } + ctrl = v4l2_ctrl_find(dev->terminal_sensor.sd->ctrl_handler, + V4L2_CID_ANALOGUE_GAIN); + v4l2_ctrl_s_ctrl(ctrl, cur_gain); + priv->cur_gain = cur_gain; + + id = rkcif_get_exp_effect_stream_id(dev, stream->frame_idx - 1); + if (id < 0) { + dev_err(dev->dev, "%s %d get exp_effect stream failed\n", + __func__, __LINE__); + return; + } + priv = dev->sditf[id]; + if (stream->frame_idx == 0) { + for (i = 0; i < dev->exp_delay.time_delay; i++) { + effect_time = kzalloc(sizeof(*effect_time), GFP_KERNEL); + if (effect_time) { + effect_time->sequence = i; + effect_time->time = priv->cur_time; + list_add_tail(&effect_time->list, &dev->effect_time_head); + effect_time = NULL; + } else { + v4l2_err(&dev->v4l2_dev, "Failed to alloc struct sditf_effect_time\n"); + } + } + for (i = 0; i < dev->exp_delay.gain_delay; i++) { + effect_gain = kzalloc(sizeof(*effect_gain), GFP_KERNEL); + if (effect_gain) { + effect_gain->sequence = i; + effect_gain->gain = priv->cur_gain; + list_add_tail(&effect_gain->list, &dev->effect_gain_head); + effect_gain = NULL; + } else { + v4l2_err(&dev->v4l2_dev, "Failed to alloc struct sditf_effect_gain\n"); + } + } + if (dev->exp_delay.time_delay >= dev->exp_delay.gain_delay) + min_delay = dev->exp_delay.gain_delay; + else + min_delay = dev->exp_delay.time_delay; + for (i = 0; i < min_delay; i++) + rkcif_update_effect_exposure(dev); + return; + } + + effect_time = kzalloc(sizeof(*effect_time), GFP_KERNEL); + if (effect_time) { + effect_time->sequence = stream->frame_idx + dev->exp_delay.time_delay - 1; + effect_time->time = cur_time; + list_add_tail(&effect_time->list, &dev->effect_time_head); + effect_time = NULL; + } else { + v4l2_err(&dev->v4l2_dev, "Failed to alloc struct sditf_effect_time\n"); + } + effect_gain = kzalloc(sizeof(*effect_gain), GFP_KERNEL); + if (effect_gain) { + effect_gain->sequence = stream->frame_idx + dev->exp_delay.gain_delay - 1; + effect_gain->gain = cur_gain; + list_add_tail(&effect_gain->list, &dev->effect_gain_head); + effect_gain = NULL; + } else { + v4l2_err(&dev->v4l2_dev, "Failed to alloc struct sditf_effect_gain\n"); + } + rkcif_update_effect_exposure(dev); + priv->frame_idx.cur_frame_idx++; + priv->frame_idx.total_frame_idx = stream->frame_idx; +} + int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int inf_id) { struct device *dev = cif_dev->dev; @@ -2299,6 +2682,7 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int cif_dev->rdbk_debug = 0; cif_dev->is_stop_skip = false; cif_dev->is_sensor_off = false; + cif_dev->exp_dbg = 0; cif_dev->resume_mode = 0; memset(&cif_dev->channels[0].capture_info, 0, sizeof(cif_dev->channels[0].capture_info)); @@ -2308,6 +2692,12 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int INIT_WORK(&cif_dev->err_state_work.work, rkcif_err_print_work); INIT_WORK(&cif_dev->sensor_work.work, rkcif_set_sensor_stream); INIT_DELAYED_WORK(&cif_dev->work_deal_err, rkcif_deal_err_intr); + INIT_WORK(&cif_dev->exp_work, rkcif_exp_work); + cif_dev->exp_delay.time_delay = 2; + cif_dev->exp_delay.gain_delay = 2; + cif_dev->is_alloc_buf_user = false; + INIT_LIST_HEAD(&cif_dev->effect_time_head); + INIT_LIST_HEAD(&cif_dev->effect_gain_head); if (cif_dev->inf_id == RKCIF_MIPI_LVDS && cif_dev->chip_id <= CHIP_RK3562_CIF) cif_dev->use_hw_interlace = false; diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index 792a1c6b9091..04dfb6eff1e2 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -197,6 +197,7 @@ struct rkcif_buffer { }; struct dma_buf *dbuf; u64 fe_timestamp; + int id; }; struct rkcif_tools_buffer { @@ -523,6 +524,7 @@ struct rkcif_stream { unsigned int crop_mask; /* lock between irq and buf_queue */ struct list_head buf_head; + struct list_head buf_head_multi_cache; struct rkcif_buffer *curr_buf; struct rkcif_buffer *next_buf; struct rkcif_rx_buffer *curr_buf_toisp; @@ -575,6 +577,7 @@ struct rkcif_stream { u32 cur_skip_frame; int thunderboot_skip_interval; int sequence; + atomic_t sub_stream_buf_cnt; bool stopping; bool crop_enable; bool crop_dyn_en; @@ -855,6 +858,12 @@ enum rkcif_interlace_mode { RKCIF_INTERLACE_HW, }; +struct rkcif_stream_info { + u32 id; + u32 frame_idx_end; + struct sditf_priv *priv; +}; + /* * struct rkcif_device - ISP platform device * @base_addr: base register address @@ -919,6 +928,12 @@ struct rkcif_device { dma_addr_t resmem_addr; size_t resmem_size; struct rk_tb_client tb_client; + struct rkcif_stream_info cur_stream; + struct rkcif_exp_delay exp_delay; + struct work_struct exp_work; + struct rkcif_dummy_buffer *buf_user[VIDEO_MAX_FRAME]; + struct list_head effect_time_head; + struct list_head effect_gain_head; bool is_start_hdr; bool reset_work_cancel; bool iommu_en; @@ -934,6 +949,7 @@ struct rkcif_device { bool use_hw_interlace; bool is_stop_skip; bool is_sensor_off; + bool is_alloc_buf_user; int rdbk_debug; struct rkcif_sync_cfg sync_cfg; int sditf_cnt; @@ -952,6 +968,7 @@ struct rkcif_device { struct delayed_work work_deal_err; u32 other_intstat[RKMODULE_MULTI_DEV_NUM]; u32 fb_res_bufs; + int exp_dbg; }; extern struct platform_driver rkcif_plat_drv; @@ -1050,6 +1067,7 @@ void rkcif_rockit_dev_deinit(void); void rkcif_err_print_work(struct work_struct *work); int rkcif_stream_suspend(struct rkcif_device *cif_dev, int mode); int rkcif_stream_resume(struct rkcif_device *cif_dev, int mode); +void rkcif_free_buf_by_user_require(struct rkcif_device *dev); static inline u64 rkcif_time_get_ns(struct rkcif_device *dev) { diff --git a/drivers/media/platform/rockchip/cif/subdev-itf.c b/drivers/media/platform/rockchip/cif/subdev-itf.c index 8b0cd4327dd8..25cf7d9907bd 100644 --- a/drivers/media/platform/rockchip/cif/subdev-itf.c +++ b/drivers/media/platform/rockchip/cif/subdev-itf.c @@ -29,6 +29,54 @@ static inline struct sditf_priv *to_sditf_priv(struct v4l2_subdev *subdev) return container_of(subdev, struct sditf_priv, sd); } +void sditf_event_inc_sof(struct sditf_priv *priv) +{ + if (priv) { + struct v4l2_event event = { + .type = V4L2_EVENT_FRAME_SYNC, + .u.frame_sync.frame_sequence = + atomic_inc_return(&priv->frm_sync_seq) - 1, + }; + v4l2_event_queue(priv->sd.devnode, &event); + if (priv->cif_dev->exp_dbg) + dev_info(priv->dev, "sof %d\n", atomic_read(&priv->frm_sync_seq) - 1); + } +} + +void sditf_event_exposure_notifier(struct sditf_priv *priv, + struct sditf_effect_exp *effect_exp) +{ + if (priv) { + struct v4l2_event event = { + .type = V4L2_EVENT_EXPOSURE, + }; + v4l2_event_queue(priv->sd.devnode, &event); + } +} + +u32 sditf_get_sof(struct sditf_priv *priv) +{ + if (priv) + return atomic_read(&priv->frm_sync_seq) - 1; + + return 0; +} + +void sditf_set_sof(struct sditf_priv *priv, u32 seq) +{ + if (priv) + atomic_set(&priv->frm_sync_seq, seq); +} + +static int sditf_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + if (sub->type == V4L2_EVENT_FRAME_SYNC || sub->type == V4L2_EVENT_EXPOSURE) + return v4l2_event_subscribe(fh, sub, RKCIF_V4L2_EVENT_ELEMS, NULL); + else + return -EINVAL; +} + static void sditf_buffree_work(struct work_struct *work) { struct sditf_work_struct *buffree_work = container_of(work, @@ -330,9 +378,15 @@ static long sditf_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) struct v4l2_subdev_format fmt; struct rkcif_device *cif_dev = priv->cif_dev; struct v4l2_subdev *sensor_sd; + struct rkcif_exp *exp; + struct rkcif_effect_exp *effect_exposure; + struct sditf_time *time; + struct sditf_gain *gain; + struct sditf_effect_exp *effect_exp; int *pbuf_num = NULL; int ret = 0; int *on = NULL; + int *connect_id = NULL; switch (cmd) { case RKISP_VICAP_CMD_MODE: @@ -384,6 +438,53 @@ static long sditf_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) return 0; } break; + case RKCIF_CMD_SET_EXPOSURE: + exp = (struct rkcif_exp *)arg; + time = kzalloc(sizeof(*time), GFP_KERNEL); + if (!time) { + ret = -ENOMEM; + return ret; + } + gain = kzalloc(sizeof(*gain), GFP_KERNEL); + if (!gain) { + ret = -ENOMEM; + kfree(time); + return ret; + } + time->time = exp->time; + gain->gain = exp->gain; + mutex_lock(&priv->mutex); + list_add_tail(&time->list, &priv->time_head); + list_add_tail(&gain->list, &priv->gain_head); + mutex_unlock(&priv->mutex); + if (cif_dev->exp_dbg) + dev_info(priv->dev, "RKCIF_CMD_SET_EXPOSURE %d\n", ret); + return ret; + case RKCIF_CMD_GET_EFFECT_EXPOSURE: + if (!list_empty(&priv->effect_exp_head)) { + effect_exp = list_first_entry(&priv->effect_exp_head, + struct sditf_effect_exp, + list); + if (effect_exp) { + effect_exposure = (struct rkcif_effect_exp *)arg; + mutex_lock(&priv->mutex); + list_del(&effect_exp->list); + mutex_unlock(&priv->mutex); + *effect_exposure = effect_exp->exp; + kfree(effect_exp); + effect_exp = NULL; + if (cif_dev->exp_dbg) + dev_info(priv->dev, "RKCIF_CMD_GET_EFFECT_EXPOSURE seq %d, time 0x%x, gain 0x%x\n", + effect_exposure->sequence, effect_exposure->time, effect_exposure->gain); + } + } else { + ret = -EINVAL; + } + return ret; + case RKCIF_CMD_GET_CONNECT_ID: + connect_id = (int *)arg; + *connect_id = priv->connect_id; + return ret; default: break; } @@ -401,9 +502,12 @@ static long sditf_compat_ioctl32(struct v4l2_subdev *sd, struct v4l2_subdev *sensor_sd; struct rkisp_vicap_mode *mode; struct rkmodule_hdr_cfg *hdr_cfg; + struct rkcif_exp *exp; + struct rkcif_effect_exp *effect_expsure; int buf_num; int ret = 0; int on; + int connect_id = 0; switch (cmd) { case RKISP_VICAP_CMD_MODE: @@ -430,11 +534,48 @@ static long sditf_compat_ioctl32(struct v4l2_subdev *sd, ret = -ENOMEM; return ret; } - if (copy_from_user(hdr_cfg, up, sizeof(*hdr_cfg))) { - kfree(hdr_cfg); + ret = sditf_ioctl(sd, cmd, hdr_cfg); + if (!ret) { + ret = copy_to_user(up, hdr_cfg, sizeof(*hdr_cfg)); + if (ret) + ret = -EFAULT; + } + kfree(hdr_cfg); + return ret; + case RKCIF_CMD_SET_EXPOSURE: + exp = kzalloc(sizeof(*exp), GFP_KERNEL); + if (!exp) { + ret = -ENOMEM; + return ret; + } + if (copy_from_user(exp, up, sizeof(*exp))) { + kfree(exp); return -EFAULT; } - ret = sditf_ioctl(sd, cmd, hdr_cfg); + ret = sditf_ioctl(sd, cmd, exp); + kfree(exp); + return ret; + case RKCIF_CMD_GET_EFFECT_EXPOSURE: + effect_expsure = kzalloc(sizeof(*effect_expsure), GFP_KERNEL); + if (!effect_expsure) { + ret = -ENOMEM; + return ret; + } + ret = sditf_ioctl(sd, cmd, effect_expsure); + if (!ret) { + ret = copy_to_user(up, effect_expsure, sizeof(*effect_expsure)); + if (ret) + ret = -EFAULT; + } + kfree(effect_expsure); + return ret; + case RKCIF_CMD_GET_CONNECT_ID: + ret = sditf_ioctl(sd, cmd, &connect_id); + if (!ret) { + ret = copy_to_user(up, &connect_id, sizeof(int)); + if (ret) + ret = -EFAULT; + } return ret; case RKISP_VICAP_CMD_QUICK_STREAM: if (copy_from_user(&on, up, sizeof(int))) @@ -1018,6 +1159,8 @@ static const struct v4l2_subdev_video_ops sditf_video_ops = { }; static const struct v4l2_subdev_core_ops sditf_core_ops = { + .subscribe_event = sditf_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, .ioctl = sditf_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl32 = sditf_compat_ioctl32, @@ -1058,6 +1201,7 @@ static int rkcif_sditf_attach_cifdev(struct sditf_priv *sditf) cif_dev->sditf[cif_dev->sditf_cnt] = sditf; sditf->cif_dev = cif_dev; + sditf->connect_id = cif_dev->sditf_cnt; cif_dev->sditf_cnt++; return 0; @@ -1130,6 +1274,32 @@ static const struct v4l2_ctrl_ops rkcif_sditf_ctrl_ops = { .g_volatile_ctrl = rkcif_sditf_get_ctrl, }; +void sditf_get_default_exp(struct sditf_priv *sditf) +{ + struct v4l2_ctrl *ctrl = NULL; + struct rkcif_device *dev = sditf->cif_dev; + + if (dev->terminal_sensor.sd == NULL) + return; + ctrl = v4l2_ctrl_find(dev->terminal_sensor.sd->ctrl_handler, + V4L2_CID_EXPOSURE); + if (ctrl) + sditf->cur_time = ctrl->default_value; + else + sditf->cur_time = 16; + + ctrl = v4l2_ctrl_find(dev->terminal_sensor.sd->ctrl_handler, + V4L2_CID_ANALOGUE_GAIN); + if (ctrl) + sditf->cur_gain = ctrl->default_value; + else + sditf->cur_gain = 16; + + if (dev->exp_dbg) + dev_info(sditf->dev, "get default time 0x%x gain 0x%x\n", + sditf->cur_time, sditf->cur_gain); +} + static int sditf_notifier_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd) @@ -1264,6 +1434,12 @@ static int rkcif_subdev_media_init(struct sditf_priv *priv) atomic_set(&priv->stream_cnt, 0); INIT_WORK(&priv->buffree_work.work, sditf_buffree_work); INIT_LIST_HEAD(&priv->buf_free_list); + INIT_LIST_HEAD(&priv->time_head); + INIT_LIST_HEAD(&priv->gain_head); + INIT_LIST_HEAD(&priv->effect_exp_head); + priv->frame_idx.cur_frame_idx = 0; + atomic_set(&priv->frm_sync_seq, 0); + mutex_init(&priv->mutex); return 0; } @@ -1282,7 +1458,8 @@ static int rkcif_subdev_probe(struct platform_device *pdev) sd = &priv->sd; v4l2_subdev_init(sd, &sditf_subdev_ops); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->owner = THIS_MODULE; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; snprintf(sd->name, sizeof(sd->name), "rockchip-cif-sditf"); sd->dev = dev; diff --git a/drivers/media/platform/rockchip/cif/subdev-itf.h b/drivers/media/platform/rockchip/cif/subdev-itf.h index 58c63094a3c8..c691c30f0540 100644 --- a/drivers/media/platform/rockchip/cif/subdev-itf.h +++ b/drivers/media/platform/rockchip/cif/subdev-itf.h @@ -59,6 +59,38 @@ struct sditf_work_struct { struct rkisp_rx_buffer *buf; }; +struct sditf_frame_idx { + u32 cur_frame_idx; + u32 total_frame_idx; +}; + +struct sditf_time { + struct list_head list; + u32 time; +}; + +struct sditf_gain { + struct list_head list; + u32 gain; +}; + +struct sditf_effect_time { + struct list_head list; + u32 sequence; + u32 time; +}; + +struct sditf_effect_gain { + struct list_head list; + u32 sequence; + u32 gain; +}; + +struct sditf_effect_exp { + struct list_head list; + struct rkcif_effect_exp exp; +}; + struct sditf_priv { struct device *dev; struct v4l2_async_notifier notifier; @@ -74,16 +106,32 @@ struct sditf_priv { struct v4l2_subdev *sensor_sd; struct sditf_work_struct buffree_work; struct list_head buf_free_list; + struct sditf_frame_idx frame_idx; + struct mutex mutex; + atomic_t frm_sync_seq; int buf_num; int num_sensors; int combine_index; + int connect_id; bool is_combine_mode; atomic_t power_cnt; atomic_t stream_cnt; + struct list_head time_head; + struct list_head gain_head; + struct list_head effect_exp_head; + u32 cur_time; + u32 cur_gain; + int one_to_multi_id; }; extern struct platform_driver rkcif_subdev_driver; void sditf_change_to_online(struct sditf_priv *priv); void sditf_disable_immediately(struct sditf_priv *priv); +void sditf_event_exposure_notifier(struct sditf_priv *priv, + struct sditf_effect_exp *effect_exp); +void sditf_event_inc_sof(struct sditf_priv *priv); +u32 sditf_get_sof(struct sditf_priv *priv); +void sditf_set_sof(struct sditf_priv *priv, u32 seq); +void sditf_get_default_exp(struct sditf_priv *sditf); #endif