diff --git a/drivers/media/platform/rockchip/cif/Kconfig b/drivers/media/platform/rockchip/cif/Kconfig index 761f942f07a6..04944b0ef987 100644 --- a/drivers/media/platform/rockchip/cif/Kconfig +++ b/drivers/media/platform/rockchip/cif/Kconfig @@ -37,3 +37,42 @@ config ROCKCHIP_CIF_USE_NONE_DUMMY_BUF endchoice +config ROCKCHIP_CIF_USE_MONITOR + bool "rkcif use monitor" + depends on VIDEO_ROCKCHIP_CIF + default n + help + Support for CIF to monitor capture error. + +config ROCKCHIP_CIF_MONITOR_MODE + hex "rkcif monitor mode" + default 0x1 + depends on ROCKCHIP_CIF_USE_MONITOR + +config ROCKCHIP_CIF_MONITOR_START_FRAME + hex "the frame id to start monitor" + default 0 + depends on ROCKCHIP_CIF_USE_MONITOR + +config ROCKCHIP_CIF_MONITOR_CYCLE + hex "frame num of monitoring cycle" + default 0x8 + depends on ROCKCHIP_CIF_USE_MONITOR + +config ROCKCHIP_CIF_MONITOR_KEEP_TIME + hex "timeout for keep monitoring after finding out error, unit(ms)" + default 0x3e8 + depends on ROCKCHIP_CIF_USE_MONITOR + +config ROCKCHIP_CIF_MONITOR_ERR_CNT + hex "error reference val for resetting" + default 0x5 + depends on ROCKCHIP_CIF_USE_MONITOR + +config ROCKCHIP_CIF_RESET_BY_USER + bool "rkcif reset by user" + depends on ROCKCHIP_CIF_USE_MONITOR + default n + help + Support for CIF to reset pipe by user. + diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 20c9aaf440b5..96945efd8a59 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -2800,6 +2800,7 @@ static int rkcif_csi_stream_start(struct rkcif_stream *stream, unsigned int mode if (stream->state < RKCIF_STATE_STREAMING) { stream->frame_idx = 0; + stream->buf_wake_up_cnt = 0; stream->frame_phase = 0; stream->lack_buf_cnt = 0; } @@ -4153,6 +4154,7 @@ static int rkcif_stream_start(struct rkcif_stream *stream, unsigned int mode) if (stream->state < RKCIF_STATE_STREAMING) { stream->frame_idx = 0; + stream->buf_wake_up_cnt = 0; stream->lack_buf_cnt = 0; stream->frame_phase = 0; } @@ -4494,6 +4496,8 @@ static void rkcif_attach_sync_mode(struct rkcif_hw *hw) mutex_unlock(&hw->dev_lock); } +static void rkcif_monitor_reset_event(struct rkcif_device *dev); + int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode) { struct rkcif_vdev_node *node = &stream->vnode; @@ -4668,6 +4672,7 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode) } dev->reset_work_cancel = false; stream->cur_stream_mode |= mode; + rkcif_monitor_reset_event(dev); goto out; stop_stream: @@ -5454,6 +5459,9 @@ void rkcif_set_fps(struct rkcif_stream *stream, struct rkcif_fps *fps) skip_n); } +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, bool valid_prio, unsigned int cmd, void *arg) { @@ -5463,6 +5471,7 @@ static long rkcif_ioctl_default(struct file *file, void *fh, struct v4l2_rect rect; struct csi_channel_info csi_info; struct rkcif_fps fps; + int reset_src; switch (cmd) { case RKCIF_CMD_GET_CSI_MEMORY_MODE: @@ -5508,6 +5517,9 @@ static long rkcif_ioctl_default(struct file *file, void *fh, fps = *(struct rkcif_fps *)arg; rkcif_set_fps(stream, &fps); break; + case RKCIF_CMD_SET_RESET: + reset_src = *(int *)arg; + return rkcif_do_reset_work(dev, reset_src); default: return -EINVAL; } @@ -5864,10 +5876,11 @@ static int rkcif_lvds_sd_s_power(struct v4l2_subdev *sd, int on) static int rkcif_sof_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, struct v4l2_event_subscription *sub) { - if (sub->type != V4L2_EVENT_FRAME_SYNC) + if (sub->type == V4L2_EVENT_FRAME_SYNC || + sub->type == V4L2_EVENT_RESET_DEV) + return v4l2_event_subscribe(fh, sub, RKCIF_V4L2_EVENT_ELEMS, NULL); + else return -EINVAL; - - return v4l2_event_subscribe(fh, sub, RKCIF_V4L2_EVENT_ELEMS, NULL); } static const struct media_entity_operations rkcif_lvds_sd_media_ops = { @@ -6092,10 +6105,6 @@ void rkcif_vb_done_oneframe(struct rkcif_stream *stream, stream->pixm.plane_fmt[i].sizeimage); } - if (stream->cifdev->hdr.hdr_mode == NO_HDR || - stream->cifdev->hdr.hdr_mode == HDR_COMPR) - vb_done->vb2_buf.timestamp = ktime_get_ns(); - vb2_buffer_done(&vb_done->vb2_buf, VB2_BUF_STATE_DONE); v4l2_dbg(2, rkcif_debug, &stream->cifdev->v4l2_dev, "stream[%d] vb done, index: %d, sequence %d, dma_en 0x%x\n", stream->id, @@ -6530,40 +6539,54 @@ static void rkcif_dynamic_crop(struct rkcif_stream *stream) static void rkcif_monitor_reset_event(struct rkcif_device *dev) { - struct rkcif_stream *stream = &dev->stream[RKCIF_STREAM_MIPI_ID0]; + struct rkcif_stream *stream = NULL; struct rkcif_timer *timer = &dev->reset_watchdog_timer; unsigned int cycle = 0; u64 fps, timestamp0, timestamp1; unsigned long flags, fps_flags; + int i = 0; + + if (timer->is_running) + return; if (timer->monitor_mode == RKCIF_MONITOR_MODE_IDLE) return; - if (stream->state != RKCIF_STATE_STREAMING) - return; + for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { + stream = &dev->stream[i]; + if (stream->state == RKCIF_STATE_STREAMING) + break; + } - if (timer->is_running) + if (i >= RKCIF_MAX_STREAM_MIPI) return; timer->is_triggered = rkcif_is_triggered_monitoring(dev); if (timer->is_triggered) { - struct v4l2_rect *raw_rect = &dev->terminal_sensor.raw_rect; enum rkcif_monitor_mode mode; s32 vblank = 0; u32 vts = 0; + u64 numerator = 0; + u64 denominator = 0; - spin_lock_irqsave(&stream->fps_lock, fps_flags); - timestamp0 = stream->fps_stats.frm0_timestamp; - timestamp1 = stream->fps_stats.frm1_timestamp; - spin_unlock_irqrestore(&stream->fps_lock, fps_flags); + if (stream->frame_idx > 2) { + spin_lock_irqsave(&stream->fps_lock, fps_flags); + timestamp0 = stream->fps_stats.frm0_timestamp; + timestamp1 = stream->fps_stats.frm1_timestamp; + spin_unlock_irqrestore(&stream->fps_lock, fps_flags); + fps = timestamp0 > timestamp1 ? + timestamp0 - timestamp1 : timestamp1 - timestamp0; + fps = div_u64(fps, 1000); + } else { + numerator = dev->terminal_sensor.fi.interval.numerator; + denominator = dev->terminal_sensor.fi.interval.denominator; + fps = div_u64(1000000 * numerator, denominator); + } spin_lock_irqsave(&timer->timer_lock, flags); - fps = timestamp0 > timestamp1 ? - timestamp0 - timestamp1 : timestamp1 - timestamp0; - fps = div_u64(fps, 1000); timer->frame_end_cycle_us = fps; vblank = rkcif_get_sensor_vblank(dev); @@ -6579,7 +6602,11 @@ static void rkcif_monitor_reset_event(struct rkcif_device *dev) timer->run_cnt = 0; timer->is_running = true; timer->is_buf_stop_update = false; - timer->last_buf_wakeup_cnt = dev->buf_wake_up_cnt; + for (i = 0; i < dev->num_channels; i++) { + stream = &dev->stream[i]; + if (stream->state == RKCIF_STATE_STREAMING) + timer->last_buf_wakeup_cnt[i] = stream->buf_wake_up_cnt; + } /* in trigger mode, monitoring count is fps */ mode = timer->monitor_mode; if (mode == RKCIF_MONITOR_MODE_CONTINUE || @@ -6916,7 +6943,6 @@ static void rkcif_line_wake_up(struct rkcif_stream *stream, int mipi_id) { u32 mode; struct rkcif_buffer *active_buf = NULL; - struct rkcif_device *cif_dev = stream->cifdev; int ret = 0; mode = stream->line_int_cnt % 2; @@ -6934,12 +6960,8 @@ static void rkcif_line_wake_up(struct rkcif_stream *stream, int mipi_id) } ret = rkcif_get_new_buffer_wake_up_mode(stream); if (ret) - goto end_wake_up; - + return; rkcif_buf_done_prepare(stream, active_buf, mipi_id, mode); -end_wake_up: - if (mipi_id == RKCIF_STREAM_MIPI_ID0) - cif_dev->buf_wake_up_cnt += 1; } static void rkcif_deal_readout_time(struct rkcif_stream *stream) @@ -6998,8 +7020,6 @@ static void rkcif_update_stream(struct rkcif_device *cif_dev, stream->fps_stats.frm1_timestamp = ktime_get_ns(); } spin_unlock_irqrestore(&stream->fps_lock, flags); - if (mipi_id == RKCIF_STREAM_MIPI_ID0) - cif_dev->buf_wake_up_cnt += 1; } if (cif_dev->inf_id == RKCIF_MIPI_LVDS) @@ -7097,16 +7117,13 @@ static int rkcif_do_reset_work(struct rkcif_device *cif_dev, struct rkcif_timer *timer = &cif_dev->reset_watchdog_timer; int i, j, ret = 0; u32 on, sof_cnt; - u64 fps; + int capture_mode = 0; mutex_lock(&cif_dev->stream_lock); - if (cif_dev->reset_work_cancel) goto unlock_stream; - v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, "do rkcif reset\n"); - fps = div_u64(timer->frame_end_cycle_us, 1000); for (i = 0, j = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { stream = &cif_dev->stream[i]; @@ -7115,15 +7132,7 @@ static int rkcif_do_reset_work(struct rkcif_device *cif_dev, v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, "stream[%d] stopping\n", stream->id); - stream->stopping = true; - - ret = wait_event_timeout(stream->wq_stopped, - stream->state != RKCIF_STATE_STREAMING, - msecs_to_jiffies(fps)); - if (!ret) { - rkcif_stream_stop(stream); - stream->stopping = false; - } + rkcif_stream_stop(stream); if (stream->id == RKCIF_STREAM_MIPI_ID0) { sof_cnt = rkcif_get_sof(cif_dev); @@ -7134,9 +7143,7 @@ static int rkcif_do_reset_work(struct rkcif_device *cif_dev, stream->frame_idx, sof_cnt); - resume_info->frm_sync_seq = sof_cnt; - if (stream->frame_idx != sof_cnt) - stream->frame_idx = sof_cnt; + resume_info->frm_sync_seq = stream->frame_idx; } stream->state = RKCIF_STATE_RESET_IN_STREAMING; @@ -7157,10 +7164,7 @@ static int rkcif_do_reset_work(struct rkcif_device *cif_dev, if (p->subdevs[i] == terminal_sensor->sd) { - if (reset_src == RKCIF_RESET_SRC_ERR_CSI2 || - reset_src == RKCIF_RESET_SRC_ERR_HOTPLUG || - reset_src == RKICF_RESET_SRC_ERR_CUTOFF) { - + if (reset_src != RKCIF_RESET_SRC_ERR_APP) { ret = v4l2_subdev_call(p->subdevs[i], core, ioctl, RKMODULE_SET_QUICK_STREAM, &on); if (ret) @@ -7170,25 +7174,35 @@ static int rkcif_do_reset_work(struct rkcif_device *cif_dev, } else { ret = v4l2_subdev_call(p->subdevs[i], video, s_stream, on); } - if (ret) v4l2_err(&cif_dev->v4l2_dev, "%s:stream %s subdev:%s failed\n", __func__, on ? "on" : "off", p->subdevs[i]->name); + } + for (i = 0; i < cif_dev->sditf_cnt; i++) { + if (cif_dev->sditf[i] && cif_dev->sditf[i]->sensor_sd) + ret = v4l2_subdev_call(cif_dev->sditf[i]->sensor_sd, core, ioctl, + RKMODULE_SET_QUICK_STREAM, &on); } rockchip_clear_system_status(SYS_STATUS_CIF0); - rkcif_do_cru_reset(cif_dev); + if (cif_dev->chip_id >= CHIP_RK3588_CIF) { + rkcif_do_soft_reset(cif_dev); + } else { - rkcif_disable_sys_clk(cif_dev->hw_dev); + rkcif_do_cru_reset(cif_dev); - udelay(5); + rkcif_disable_sys_clk(cif_dev->hw_dev); - ret = rkcif_enable_sys_clk(cif_dev->hw_dev); - if (ret < 0) { - v4l2_err(&cif_dev->v4l2_dev, "%s:resume cif clk failed\n", __func__); - goto unlock_stream; + udelay(5); + + ret = rkcif_enable_sys_clk(cif_dev->hw_dev); + + if (ret < 0) { + v4l2_err(&cif_dev->v4l2_dev, "%s:resume cif clk failed\n", __func__); + goto unlock_stream; + } } for (i = 0; i < j; i++) { @@ -7207,7 +7221,17 @@ static int rkcif_do_reset_work(struct rkcif_device *cif_dev, stream->curr_buf = NULL; stream->next_buf = NULL; } - ret = rkcif_csi_stream_start(stream, RKCIF_STREAM_MODE_CAPTURE); + if (!cif_dev->sditf[0] || cif_dev->sditf[0]->toisp_inf.link_mode == TOISP_NONE) + capture_mode = RKCIF_STREAM_MODE_CAPTURE; + else + capture_mode = RKCIF_STREAM_MODE_TOISP; + if (cif_dev->active_sensor && + (cif_dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY || + cif_dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY || + cif_dev->active_sensor->mbus.type == V4L2_MBUS_CCP2)) + ret = rkcif_csi_stream_start(stream, capture_mode); + else + ret = rkcif_stream_start(stream, capture_mode); if (ret) { v4l2_err(&cif_dev->v4l2_dev, "%s:resume stream[%d] failed\n", __func__, stream->id); @@ -7229,9 +7253,7 @@ static int rkcif_do_reset_work(struct rkcif_device *cif_dev, rkcif_set_sof(cif_dev, resume_info->frm_sync_seq); - if (reset_src == RKCIF_RESET_SRC_ERR_CSI2 || - reset_src == RKCIF_RESET_SRC_ERR_HOTPLUG || - reset_src == RKICF_RESET_SRC_ERR_CUTOFF) { + if (reset_src != RKCIF_RESET_SRC_ERR_APP) { ret = v4l2_subdev_call(p->subdevs[i], core, ioctl, RKMODULE_SET_QUICK_STREAM, &on); if (ret) @@ -7251,14 +7273,20 @@ static int rkcif_do_reset_work(struct rkcif_device *cif_dev, p->subdevs[i]->name); } - rkcif_start_luma(&cif_dev->luma_vdev, - cif_dev->stream[RKCIF_STREAM_MIPI_ID0].cif_fmt_in); + for (i = 0; i < cif_dev->sditf_cnt; i++) { + if (cif_dev->sditf[i] && cif_dev->sditf[i]->sensor_sd) + ret = v4l2_subdev_call(cif_dev->sditf[i]->sensor_sd, core, ioctl, + RKMODULE_SET_QUICK_STREAM, &on); + } + + if (cif_dev->chip_id < CHIP_RK3588_CIF) + rkcif_start_luma(&cif_dev->luma_vdev, + cif_dev->stream[RKCIF_STREAM_MIPI_ID0].cif_fmt_in); timer->csi2_err_triggered_cnt = 0; rkcif_monitor_reset_event(cif_dev); v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, "do rkcif reset successfully!\n"); - mutex_unlock(&cif_dev->stream_lock); return 0; @@ -7275,14 +7303,11 @@ void rkcif_reset_work(struct work_struct *work) struct rkcif_device *dev = container_of(reset_work, struct rkcif_device, reset_work); - struct rkcif_timer *timer = &dev->reset_watchdog_timer; int ret; ret = rkcif_do_reset_work(dev, reset_work->reset_src); if (ret) v4l2_info(&dev->v4l2_dev, "do reset work failed!\n"); - timer->is_running = false; - timer->has_been_init = false; } static bool rkcif_is_reduced_frame_rate(struct rkcif_device *dev) @@ -7294,6 +7319,8 @@ static bool rkcif_is_reduced_frame_rate(struct rkcif_device *dev) unsigned long fps_flags; unsigned int deviation = 1; bool is_reduced = false; + u64 cur_time = 0; + u64 time_distance = 0; spin_lock_irqsave(&stream->fps_lock, fps_flags); timestamp0 = stream->fps_stats.frm0_timestamp; @@ -7310,6 +7337,13 @@ static bool rkcif_is_reduced_frame_rate(struct rkcif_device *dev) v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "diff_time:%lld,devi_t:%ld,devi_h:%d\n", diff_time, timer->line_end_cycle * deviation, deviation); + cur_time = ktime_get_ns(); + time_distance = timestamp0 > timestamp1 ? + cur_time - timestamp0 : cur_time - timestamp1; + time_distance = div_u64(time_distance, 1000); + if (time_distance > fps * 2) + return false; + if (diff_time > timer->line_end_cycle * deviation) { s32 vblank = 0; unsigned int vts; @@ -7347,82 +7381,110 @@ static bool rkcif_is_reduced_frame_rate(struct rkcif_device *dev) } +static void rkcif_dvp_event_reset_pipe(struct rkcif_device *dev, int reset_src) +{ + struct rkcif_dvp_sof_subdev *subdev = &dev->dvp_sof_subdev; + + if (subdev) { + struct v4l2_event event = { + .type = V4L2_EVENT_RESET_DEV, + .reserved[0] = reset_src, + }; + v4l2_event_queue(subdev->sd.devnode, &event); + } +} + +static void rkcif_lvds_event_reset_pipe(struct rkcif_device *dev, int reset_src) +{ + struct rkcif_lvds_subdev *subdev = &dev->lvds_subdev; + + if (subdev) { + struct v4l2_event event = { + .type = V4L2_EVENT_RESET_DEV, + .reserved[0] = reset_src, + }; + v4l2_event_queue(subdev->sd.devnode, &event); + } +} + +static void rkcif_send_reset_event(struct rkcif_device *cif_dev, int reset_src) +{ + struct v4l2_mbus_config *mbus = &cif_dev->active_sensor->mbus; + struct csi2_dev *csi; + + if (mbus->type == V4L2_MBUS_CSI2_DPHY || + mbus->type == V4L2_MBUS_CSI2_CPHY) { + csi = container_of(cif_dev->active_sensor->sd, struct csi2_dev, sd); + rkcif_csi2_event_reset_pipe(csi, reset_src); + } else if (mbus->type == V4L2_MBUS_CCP2) { + rkcif_lvds_event_reset_pipe(cif_dev, reset_src); + } else { + rkcif_dvp_event_reset_pipe(cif_dev, reset_src); + } + v4l2_dbg(3, rkcif_debug, &cif_dev->v4l2_dev, + "send reset event,bus type 0x%x\n", + mbus->type); +} + static void rkcif_init_reset_work(struct rkcif_timer *timer) { struct rkcif_device *dev = container_of(timer, struct rkcif_device, reset_watchdog_timer); + struct rkcif_stream *stream = NULL; unsigned long flags; - - if (timer->has_been_init) - return; + int i = 0; v4l2_info(&dev->v4l2_dev, "do reset work schedule, run_cnt:%d, reset source:%d\n", timer->run_cnt, timer->reset_src); spin_lock_irqsave(&timer->timer_lock, flags); - timer->is_running = true; + timer->is_running = false; timer->is_triggered = false; timer->csi2_err_cnt_odd = 0; timer->csi2_err_cnt_even = 0; timer->csi2_err_fs_fe_cnt = 0; timer->notifer_called_cnt = 0; - timer->last_buf_wakeup_cnt = dev->buf_wake_up_cnt; + for (i = 0; i < dev->num_channels; i++) { + stream = &dev->stream[i]; + if (stream->state == RKCIF_STATE_STREAMING) + timer->last_buf_wakeup_cnt[stream->id] = stream->buf_wake_up_cnt; + } spin_unlock_irqrestore(&timer->timer_lock, flags); - - dev->reset_work.reset_src = timer->reset_src; - if (schedule_work(&dev->reset_work.work)) { - timer->has_been_init = true; - v4l2_info(&dev->v4l2_dev, - "schedule reset work successfully\n"); + if (timer->is_ctrl_by_user) { + rkcif_send_reset_event(dev, timer->reset_src); } else { - v4l2_info(&dev->v4l2_dev, - "schedule reset work failed\n"); + if (!schedule_work(&dev->reset_work.work)) + v4l2_info(&dev->v4l2_dev, + "schedule reset work failed\n"); + dev->reset_work.reset_src = timer->reset_src; } } -void rkcif_reset_watchdog_timer_handler(struct timer_list *t) +static int rkcif_detect_reset_event(struct rkcif_stream *stream, + struct rkcif_timer *timer, + int check_cnt, + bool *is_mod_timer) { - struct rkcif_timer *timer = container_of(t, struct rkcif_timer, timer); - struct rkcif_device *dev = container_of(timer, - struct rkcif_device, - reset_watchdog_timer); + struct rkcif_device *dev = stream->cifdev; struct rkcif_sensor_info *terminal_sensor = &dev->terminal_sensor; - unsigned long flags; - unsigned int i, stream_num = 1; int ret, is_reset = 0; struct rkmodule_vicap_reset_info rst_info; - if (dev->hdr.hdr_mode == NO_HDR || dev->hdr.hdr_mode == HDR_COMPR) { - i = 0; - if (dev->stream[i].state != RKCIF_STATE_STREAMING) - goto end_detect; - } else { - if (dev->hdr.hdr_mode == HDR_X3) - stream_num = 3; - else if (dev->hdr.hdr_mode == HDR_X2) - stream_num = 2; - - for (i = 0; i < stream_num; i++) { - if (dev->stream[i].state != RKCIF_STATE_STREAMING) - goto end_detect; - } - } - - timer->run_cnt += 1; - - if (timer->last_buf_wakeup_cnt < dev->buf_wake_up_cnt) { + if (timer->last_buf_wakeup_cnt[stream->id] < stream->buf_wake_up_cnt && + check_cnt == 0) { v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "info: frame end still update(%d, %d) in detecting cnt:%d, mode:%d\n", - timer->last_buf_wakeup_cnt, dev->buf_wake_up_cnt, + timer->last_buf_wakeup_cnt[stream->id], stream->frame_idx, timer->run_cnt, timer->monitor_mode); - timer->last_buf_wakeup_cnt = dev->buf_wake_up_cnt; + timer->last_buf_wakeup_cnt[stream->id] = stream->buf_wake_up_cnt; - rkcif_is_reduced_frame_rate(dev); + if (stream->frame_idx > 2) + rkcif_is_reduced_frame_rate(dev); if (timer->monitor_mode == RKCIF_MONITOR_MODE_HOTPLUG) { ret = v4l2_subdev_call(terminal_sensor->sd, @@ -7434,11 +7496,15 @@ void rkcif_reset_watchdog_timer_handler(struct timer_list *t) else is_reset = rst_info.is_reset; rst_info.is_reset = 0; - timer->reset_src = RKCIF_RESET_SRC_ERR_HOTPLUG; + if (is_reset) + timer->reset_src = RKCIF_RESET_SRC_ERR_HOTPLUG; v4l2_subdev_call(terminal_sensor->sd, core, ioctl, RKMODULE_SET_VICAP_RST_INFO, &rst_info); - if (!is_reset) + if (!is_reset) { is_reset = rkcif_is_csi2_err_trigger_reset(timer); + if (is_reset) + timer->reset_src = RKCIF_RESET_SRC_ERR_CSI2; + } } else if (timer->monitor_mode == RKCIF_MONITOR_MODE_CONTINUE) { is_reset = rkcif_is_csi2_err_trigger_reset(timer); } else if (timer->monitor_mode == RKCIF_MONITOR_MODE_TRIGGER) { @@ -7450,17 +7516,17 @@ void rkcif_reset_watchdog_timer_handler(struct timer_list *t) if (is_reset) { rkcif_init_reset_work(timer); - return; + return is_reset; } if (timer->monitor_mode == RKCIF_MONITOR_MODE_CONTINUE || timer->monitor_mode == RKCIF_MONITOR_MODE_HOTPLUG) { if (timer->run_cnt == timer->max_run_cnt) timer->run_cnt = 0x0; - mod_timer(&timer->timer, jiffies + timer->cycle); + *is_mod_timer = true; } else { if (timer->run_cnt <= timer->max_run_cnt) { - mod_timer(&timer->timer, jiffies + timer->cycle); + *is_mod_timer = true; } else { spin_lock_irqsave(&timer->timer_lock, flags); timer->is_triggered = false; @@ -7469,13 +7535,18 @@ void rkcif_reset_watchdog_timer_handler(struct timer_list *t) v4l2_info(&dev->v4l2_dev, "stop reset detecting!\n"); } } - } else if (timer->last_buf_wakeup_cnt == dev->buf_wake_up_cnt) { + } else if (timer->last_buf_wakeup_cnt[stream->id] == stream->buf_wake_up_cnt) { - bool is_reduced = rkcif_is_reduced_frame_rate(dev); + bool is_reduced = false; + + if (stream->frame_idx > 2) + is_reduced = rkcif_is_reduced_frame_rate(dev); + else if (timer->run_cnt < 20) + is_reduced = true; if (is_reduced) { - mod_timer(&timer->timer, jiffies + timer->cycle); - v4l2_info(&dev->v4l2_dev, "%s fps is reduced\n", __func__); + *is_mod_timer = true; + v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, "%s fps is reduced\n", __func__); } else { v4l2_info(&dev->v4l2_dev, @@ -7484,20 +7555,53 @@ void rkcif_reset_watchdog_timer_handler(struct timer_list *t) timer->reset_src = RKICF_RESET_SRC_ERR_CUTOFF; rkcif_init_reset_work(timer); + is_reset = true; } } - return; -end_detect: + return is_reset; - spin_lock_irqsave(&timer->timer_lock, flags); - timer->is_triggered = false; - timer->is_running = false; - spin_unlock_irqrestore(&timer->timer_lock, flags); +} - v4l2_info(&dev->v4l2_dev, - "stream[%d] is stopped, stop reset detect!\n", - dev->stream[i].id); +void rkcif_reset_watchdog_timer_handler(struct timer_list *t) +{ + struct rkcif_timer *timer = container_of(t, struct rkcif_timer, timer); + struct rkcif_device *dev = container_of(timer, + struct rkcif_device, + reset_watchdog_timer); + struct rkcif_stream *stream = NULL; + unsigned long flags; + unsigned int i; + int is_reset = 0; + int check_cnt = 0; + bool is_mod_timer = false; + + for (i = 0; i < dev->num_channels; i++) { + stream = &dev->stream[i]; + if (stream->state == RKCIF_STATE_STREAMING) { + is_reset = rkcif_detect_reset_event(stream, + timer, + check_cnt, + &is_mod_timer); + check_cnt++; + if (is_reset) + break; + } + } + if (!is_reset && is_mod_timer) + mod_timer(&timer->timer, jiffies + timer->cycle); + + timer->run_cnt += 1; + + if (!check_cnt) { + spin_lock_irqsave(&timer->timer_lock, flags); + timer->is_triggered = false; + timer->is_running = false; + spin_unlock_irqrestore(&timer->timer_lock, flags); + + v4l2_info(&dev->v4l2_dev, + "all stream is stopped, stop reset detect!\n"); + } } int rkcif_reset_notifier(struct notifier_block *nb, @@ -8005,6 +8109,7 @@ static void rkcif_deal_sof(struct rkcif_device *cif_dev) ret = rkcif_check_group_sync_state(cif_dev); if (!ret) { hw->sync_config.sync_code = 0; + hw->sync_config.frame_idx++; spin_lock_irqsave(&hw->group_lock, flags); hw->sync_config.update_cache = hw->sync_config.sync_mask; if (!hw->sync_config.update_code) { @@ -8029,7 +8134,7 @@ static void rkcif_deal_sof(struct rkcif_device *cif_dev) } if (tmp_dev) { rkcif_send_sof(tmp_dev); - tmp_dev->stream[0].frame_idx++; + tmp_dev->stream[0].frame_idx = hw->sync_config.frame_idx; } } } @@ -8165,6 +8270,9 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) continue; stream = &cif_dev->stream[mipi_id]; + if (!cif_dev->sditf[0] || + cif_dev->sditf[0]->toisp_inf.link_mode == TOISP_NONE) + stream->buf_wake_up_cnt++; if (stream->stopping && !(stream->cur_stream_mode & RKCIF_STREAM_MODE_TOISP)) { @@ -8310,6 +8418,9 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) continue; stream = &cif_dev->stream[ch_id]; + if (!cif_dev->sditf[0] || + cif_dev->sditf[0]->toisp_inf.link_mode == TOISP_NONE) + stream->buf_wake_up_cnt++; if (stream->stopping) { rkcif_stream_stop(stream); diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index 5bed36db4049..7c2b2d6f20d3 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -1016,9 +1016,9 @@ static int rkcif_pipeline_set_stream(struct rkcif_pipeline *p, bool on) cif_dev->irq_stats.all_frm_end_cnt = 0; cif_dev->reset_watchdog_timer.is_triggered = false; cif_dev->reset_watchdog_timer.is_running = false; - cif_dev->reset_watchdog_timer.last_buf_wakeup_cnt = 0; + 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; - cif_dev->buf_wake_up_cnt = 0; } /* phy -> sensor */ @@ -1080,9 +1080,9 @@ static int rkcif_pipeline_set_stream(struct rkcif_pipeline *p, bool on) cif_dev->is_start_hdr = true; cif_dev->reset_watchdog_timer.is_triggered = false; cif_dev->reset_watchdog_timer.is_running = false; - cif_dev->reset_watchdog_timer.last_buf_wakeup_cnt = 0; + 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; - cif_dev->buf_wake_up_cnt = 0; } /* phy -> sensor */ @@ -1679,78 +1679,29 @@ static int rkcif_detach_hw(struct rkcif_device *cif_dev) return 0; } -static char *rkcif_get_monitor_mode(enum rkcif_monitor_mode mode) -{ - switch (mode) { - case RKCIF_MONITOR_MODE_IDLE: - return "idle"; - case RKCIF_MONITOR_MODE_CONTINUE: - return "continue"; - case RKCIF_MONITOR_MODE_TRIGGER: - return "trigger"; - case RKCIF_MONITOR_MODE_HOTPLUG: - return "hotplug"; - default: - return "unknown"; - } -} - static void rkcif_init_reset_monitor(struct rkcif_device *dev) { - struct device_node *node = dev->dev->of_node; struct rkcif_timer *timer = &dev->reset_watchdog_timer; struct notifier_block *notifier = &dev->reset_notifier; - u32 para[8]; - int i; - - if (!of_property_read_u32_array(node, - OF_CIF_MONITOR_PARA, - para, - CIF_MONITOR_PARA_NUM)) { - for (i = 0; i < CIF_MONITOR_PARA_NUM; i++) { - if (i == 0) { - timer->monitor_mode = para[0]; - v4l2_info(&dev->v4l2_dev, - "%s: timer monitor mode:%s\n", - __func__, rkcif_get_monitor_mode(timer->monitor_mode)); - } - - if (i == 1) { - timer->triggered_frame_num = para[1]; - v4l2_info(&dev->v4l2_dev, - "timer triggered frm num:%d\n", - timer->triggered_frame_num); - } - - if (i == 2) { - timer->frm_num_of_monitor_cycle = para[2]; - v4l2_info(&dev->v4l2_dev, - "timer frm num of monitor cycle:%d\n", - timer->frm_num_of_monitor_cycle); - } - - if (i == 3) { - timer->err_time_interval = para[3]; - v4l2_info(&dev->v4l2_dev, - "timer err time for keeping:%d ms\n", - timer->err_time_interval); - } - - if (i == 4) { - timer->csi2_err_ref_cnt = para[4]; - v4l2_info(&dev->v4l2_dev, - "timer csi2 err ref val for resetting:%d\n", - timer->csi2_err_ref_cnt); - } - } - } else { - timer->monitor_mode = RKCIF_MONITOR_MODE_IDLE; - timer->err_time_interval = 0xffffffff; - timer->frm_num_of_monitor_cycle = 0xffffffff; - timer->triggered_frame_num = 0xffffffff; - timer->csi2_err_ref_cnt = 0xffffffff; - } +#if defined(CONFIG_ROCKCHIP_CIF_USE_MONITOR) + timer->monitor_mode = CONFIG_ROCKCHIP_CIF_MONITOR_MODE; + timer->err_time_interval = CONFIG_ROCKCHIP_CIF_MONITOR_KEEP_TIME; + timer->frm_num_of_monitor_cycle = CONFIG_ROCKCHIP_CIF_MONITOR_CYCLE; + timer->triggered_frame_num = CONFIG_ROCKCHIP_CIF_MONITOR_START_FRAME; + timer->csi2_err_ref_cnt = CONFIG_ROCKCHIP_CIF_MONITOR_ERR_CNT; + #if defined(CONFIG_ROCKCHIP_CIF_RESET_BY_USER) + timer->is_ctrl_by_user = true; + #else + timer->is_ctrl_by_user = false; + #endif +#else + timer->monitor_mode = RKCIF_MONITOR_MODE_IDLE; + timer->err_time_interval = 0xffffffff; + timer->frm_num_of_monitor_cycle = 0xffffffff; + timer->triggered_frame_num = 0xffffffff; + timer->csi2_err_ref_cnt = 0xffffffff; +#endif timer->is_running = false; timer->is_triggered = false; timer->is_buf_stop_update = false; diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index 311cd11405f0..7136dc7a5b9c 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -404,7 +404,7 @@ struct rkcif_timer { unsigned int run_cnt; unsigned int max_run_cnt; unsigned int stop_index_of_run_cnt; - unsigned int last_buf_wakeup_cnt; + unsigned int last_buf_wakeup_cnt[RKCIF_MAX_STREAM_MIPI]; unsigned long csi2_err_cnt_even; unsigned long csi2_err_cnt_odd; unsigned int csi2_err_ref_cnt; @@ -425,6 +425,7 @@ struct rkcif_timer { bool is_running; bool is_csi2_err_occurred; bool has_been_init; + bool is_ctrl_by_user; enum rkcif_monitor_mode monitor_mode; enum rkmodule_reset_src reset_src; }; @@ -518,6 +519,7 @@ struct rkcif_stream { int buf_num_toisp; u64 line_int_cnt; int lack_buf_cnt; + unsigned int buf_wake_up_cnt; struct rkcif_skip_info skip_info; bool stopping; bool crop_enable; @@ -791,7 +793,6 @@ struct rkcif_device { struct rkcif_irq_stats irq_stats; spinlock_t hdr_lock; /* lock for hdr buf sync */ struct rkcif_timer reset_watchdog_timer; - unsigned int buf_wake_up_cnt; struct notifier_block reset_notifier; /* reset for mipi csi crc err */ struct rkcif_work_struct reset_work; int id_use_cnt; diff --git a/drivers/media/platform/rockchip/cif/hw.h b/drivers/media/platform/rockchip/cif/hw.h index 0b9f6ca07411..0c7a0f70a960 100644 --- a/drivers/media/platform/rockchip/cif/hw.h +++ b/drivers/media/platform/rockchip/cif/hw.h @@ -66,6 +66,7 @@ struct rkcif_multi_sync_config { u32 sync_mask; u32 update_code; u32 update_cache; + u32 frame_idx; bool is_attach; }; diff --git a/drivers/media/platform/rockchip/cif/mipi-csi2.c b/drivers/media/platform/rockchip/cif/mipi-csi2.c index cdd2d303fcd9..ef2197c1d4fb 100644 --- a/drivers/media/platform/rockchip/cif/mipi-csi2.c +++ b/drivers/media/platform/rockchip/cif/mipi-csi2.c @@ -18,6 +18,7 @@ #include #include #include "mipi-csi2.h" +#include static int csi2_debug; module_param_named(debug_csi2, csi2_debug, int, 0644); @@ -509,6 +510,17 @@ static const struct media_entity_operations csi2_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; +void rkcif_csi2_event_reset_pipe(struct csi2_dev *csi2_dev, int reset_src) +{ + if (csi2_dev) { + struct v4l2_event event = { + .type = V4L2_EVENT_RESET_DEV, + .reserved[0] = reset_src, + }; + v4l2_event_queue(csi2_dev->sd.devnode, &event); + } +} + void rkcif_csi2_event_inc_sof(struct csi2_dev *csi2_dev) { if (csi2_dev) { @@ -538,10 +550,11 @@ void rkcif_csi2_set_sof(struct csi2_dev *csi2_dev, u32 seq) static int rkcif_csi2_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, struct v4l2_event_subscription *sub) { - if (sub->type != V4L2_EVENT_FRAME_SYNC) + if (sub->type == V4L2_EVENT_FRAME_SYNC || + sub->type == V4L2_EVENT_RESET_DEV) + return v4l2_event_subscribe(fh, sub, RKCIF_V4L2_EVENT_ELEMS, NULL); + else return -EINVAL; - - return v4l2_event_subscribe(fh, sub, RKCIF_V4L2_EVENT_ELEMS, NULL); } static int rkcif_csi2_s_power(struct v4l2_subdev *sd, int on) diff --git a/drivers/media/platform/rockchip/cif/mipi-csi2.h b/drivers/media/platform/rockchip/cif/mipi-csi2.h index 757b7dd0d691..0225e087d652 100644 --- a/drivers/media/platform/rockchip/cif/mipi-csi2.h +++ b/drivers/media/platform/rockchip/cif/mipi-csi2.h @@ -166,5 +166,6 @@ int __init rkcif_csi2_plat_drv_init(void); void __exit rkcif_csi2_plat_drv_exit(void); int rkcif_csi2_register_notifier(struct notifier_block *nb); int rkcif_csi2_unregister_notifier(struct notifier_block *nb); +void rkcif_csi2_event_reset_pipe(struct csi2_dev *csi2_dev, int reset_src); #endif