diff --git a/drivers/media/platform/rockchip/cif/Kconfig b/drivers/media/platform/rockchip/cif/Kconfig index 4f2644d603bd..7ae825d4dcf5 100644 --- a/drivers/media/platform/rockchip/cif/Kconfig +++ b/drivers/media/platform/rockchip/cif/Kconfig @@ -24,16 +24,3 @@ config ROCKCHIP_CIF_WORKMODE_ONEFRAME bool "interface works in oneframe mode" endchoice - -choice - prompt "rockchip camera sensor interface monitor mode of reset" - depends on VIDEO_ROCKCHIP_CIF - default ROCKCHIP_CIF_RESET_MONITOR_TRIGGER - -config ROCKCHIP_CIF_RESET_MONITOR_TRIGGER - bool "cif reset monitor is triggered by event" - -config ROCKCHIP_CIF_RESET_MONITOR_CONTINU - bool "cif reset monitor is opened always" - -endchoice diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 6638a20f7e6d..b04071fe881a 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -2479,7 +2479,6 @@ static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count) } } - v4l2_info(&dev->v4l2_dev, "%s successfully!\n", __func__); goto out; stop_stream: @@ -3774,16 +3773,80 @@ static int rkcif_csi_g_mipi_id(struct v4l2_device *v4l2_dev, return -EINVAL; } +static bool rkcif_is_csi2_err_trigger_reset(struct rkcif_timer *timer) +{ + struct rkcif_device *dev = container_of(timer, + struct rkcif_device, + reset_watchdog_timer); + + bool is_triggered = false; + unsigned long lock_flags; + + spin_lock_irqsave(&timer->csi2_err_lock, lock_flags); + + if (timer->csi2_err_cnt_even != 0 && + timer->csi2_err_cnt_odd != 0) { + is_triggered = true; + timer->csi2_err_cnt_odd = 0; + timer->csi2_err_cnt_even = 0; + timer->reset_src = RKCIF_RESET_SRC_ERR_CSI2; + v4l2_info(&dev->v4l2_dev, "do csi2 err reset\n"); + } + + spin_unlock_irqrestore(&timer->csi2_err_lock, lock_flags); + + return is_triggered; +} + +static bool rkcif_is_triggered_monitoring(struct rkcif_device *dev) +{ + struct rkcif_timer *timer = &dev->reset_watchdog_timer; + struct rkcif_stream *stream = &dev->stream[RKCIF_STREAM_MIPI_ID0]; + bool ret = false; + + if (timer->monitor_mode == RKCIF_MONITOR_MODE_IDLE) + ret = false; + + if (timer->monitor_mode == RKCIF_MONITOR_MODE_CONTINUE || + timer->monitor_mode == RKCIF_MONITOR_MODE_HOTPLUG) { + if (stream->frame_idx >= timer->triggered_frame_num) + ret = true; + } + + if (timer->monitor_mode == RKCIF_MONITOR_MODE_TRIGGER) { + timer->is_csi2_err_occurred = rkcif_is_csi2_err_trigger_reset(timer); + ret = timer->is_csi2_err_occurred; + } + + return ret; +} + +static s32 rkcif_get_sensor_vblank(struct rkcif_device *dev) +{ + struct rkcif_sensor_info *terminal_sensor = &dev->terminal_sensor; + struct v4l2_subdev *sd = terminal_sensor->sd; + struct v4l2_ctrl_handler *hdl = sd->ctrl_handler; + struct v4l2_ctrl *ctrl = NULL; + + if (!list_empty(&hdl->ctrls)) { + list_for_each_entry(ctrl, &hdl->ctrls, node) { + if (ctrl->id == V4L2_CID_VBLANK) + return ctrl->val; + } + } + + return 0; +} + static void rkcif_monitor_reset_event(struct rkcif_device *dev) { - struct rkcif_sensor_info *sensor = &dev->terminal_sensor; struct rkcif_stream *stream = &dev->stream[RKCIF_STREAM_MIPI_ID0]; struct rkcif_timer *timer = &dev->reset_watchdog_timer; - unsigned long lock_flags = 0; - u32 denominator = 0, numerator = 0, interval = 0; - u32 time = 60ul; + unsigned int cycle = 0; + u64 fps, timestamp0, timestamp1; + unsigned long lock_flags = 0, fps_flags = 0; - if (timer->reset_src == RKCIF_RESET_SRC_NON) + if (timer->monitor_mode == RKCIF_MONITOR_MODE_IDLE) return; if (stream->state != RKCIF_STATE_STREAMING) @@ -3792,42 +3855,59 @@ static void rkcif_monitor_reset_event(struct rkcif_device *dev) if (timer->is_running) return; - if (timer->reset_src == RKCIF_RESET_SRC_NORMAL) - timer->is_triggered = true; + timer->is_triggered = rkcif_is_triggered_monitoring(dev); - v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "%s: reset src:%d\n", - __func__, timer->reset_src); - - spin_lock_irqsave(&timer->timer_lock, lock_flags); if (timer->is_triggered) { - numerator = sensor->fi.interval.numerator; - denominator = sensor->fi.interval.denominator; - if (denominator && numerator) { - time = denominator / numerator; + struct v4l2_rect *raw_rect = &dev->terminal_sensor.raw_rect; + enum rkcif_monitor_mode mode; + s32 vblank = 0; + u32 vts = 0; - /* in non-normal err src, do monitor in 1 second */ - if (timer->reset_src == RKCIF_RESET_SRC_NORMAL) - timer->max_run_cnt = 0xffffffff - CIF_TIMEOUT_FRAME_NUM; - else - timer->max_run_cnt = time * 1; + 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); + + spin_lock_irqsave(&timer->timer_lock, 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); + timer->raw_height = raw_rect->height; + vts = timer->raw_height + vblank; + timer->vts = vts; + + timer->line_end_cycle = div_u64(timer->frame_end_cycle_us, timer->vts); + fps = div_u64(timer->frame_end_cycle_us, 1000); + cycle = fps * timer->frm_num_of_monitor_cycle; + timer->cycle = msecs_to_jiffies(cycle); - interval = DIV_ROUND_UP(1000, time); - time = interval + interval / 3; - } timer->run_cnt = 0; timer->is_running = true; timer->is_buf_stop_update = false; - timer->cycle = msecs_to_jiffies(interval); - timer->timer.expires = jiffies + msecs_to_jiffies(time); timer->last_buf_wakeup_cnt = dev->buf_wake_up_cnt; + /* in trigger mode, monitoring count is fps */ + mode = timer->monitor_mode; + if (mode == RKCIF_MONITOR_MODE_CONTINUE || + mode == RKCIF_MONITOR_MODE_HOTPLUG) + timer->max_run_cnt = 0xffffffff - CIF_TIMEOUT_FRAME_NUM; + else + timer->max_run_cnt = div_u64(1000, fps) * 1; + + timer->timer.expires = jiffies + timer->cycle; mod_timer(&timer->timer, timer->timer.expires); - v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "%s:timer init inter:%ld, cycle:%ld\n", - __func__, timer->timer.expires, timer->cycle); - } - spin_unlock_irqrestore(&timer->timer_lock, lock_flags); + spin_unlock_irqrestore(&timer->timer_lock, lock_flags); + v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, + "%s:mode:%d, raw height:%d,vblank:%d, cycle:%ld, fps:%llu\n", + __func__, timer->monitor_mode, raw_rect->height, + vblank, timer->cycle, div_u64(1000, fps)); + } } static void rkcif_rdbk_frame_end(struct rkcif_stream *stream) @@ -3898,8 +3978,6 @@ static void rkcif_rdbk_frame_end(struct rkcif_stream *stream) rkcif_vb_done_oneframe(stream, &dev->rdbk_buf[RDBK_L]->vb); rkcif_vb_done_oneframe(stream, &dev->rdbk_buf[RDBK_M]->vb); rkcif_vb_done_oneframe(stream, &dev->rdbk_buf[RDBK_S]->vb); - dev->buf_wake_up_cnt += 1; - rkcif_monitor_reset_event(dev); } else { if (!dev->rdbk_buf[RDBK_L]) v4l2_err(&dev->v4l2_dev, "lost long frames\n"); @@ -3946,8 +4024,6 @@ static void rkcif_rdbk_frame_end(struct rkcif_stream *stream) dev->rdbk_buf[RDBK_L]->vb.sequence; rkcif_vb_done_oneframe(stream, &dev->rdbk_buf[RDBK_L]->vb); rkcif_vb_done_oneframe(stream, &dev->rdbk_buf[RDBK_M]->vb); - dev->buf_wake_up_cnt += 1; - rkcif_monitor_reset_event(dev); } else { if (!dev->rdbk_buf[RDBK_L]) v4l2_err(&dev->v4l2_dev, "lost long frames\n"); @@ -3991,14 +4067,19 @@ static void rkcif_update_stream(struct rkcif_device *cif_dev, struct vb2_v4l2_buffer *vb_done = NULL; unsigned long lock_flags = 0; + spin_lock(&stream->fps_lock); if (stream->frame_phase & CIF_CSI_FRAME1_READY) { if (stream->next_buf) active_buf = stream->next_buf; + stream->fps_stats.frm1_timestamp = ktime_get_ns(); } else if (stream->frame_phase & CIF_CSI_FRAME0_READY) { if (stream->curr_buf) active_buf = stream->curr_buf; + stream->fps_stats.frm0_timestamp = ktime_get_ns(); } + spin_unlock(&stream->fps_lock); + cif_dev->buf_wake_up_cnt += 1; rkcif_assign_new_buffer_pingpong(stream, 0, mipi_id); if (cif_dev->chip_id == CHIP_RV1126_CIF || @@ -4010,24 +4091,13 @@ static void rkcif_update_stream(struct rkcif_device *cif_dev, vb_done = &active_buf->vb; vb_done->vb2_buf.timestamp = ktime_get_ns(); vb_done->sequence = stream->frame_idx; - spin_lock(&stream->fps_lock); - if (stream->frame_phase & CIF_CSI_FRAME0_READY) - stream->fps_stats.frm0_timestamp = vb_done->vb2_buf.timestamp; - else if (stream->frame_phase & CIF_CSI_FRAME1_READY) - stream->fps_stats.frm1_timestamp = vb_done->vb2_buf.timestamp; - spin_unlock(&stream->fps_lock); } if (cif_dev->hdr.mode == NO_HDR) { if (active_buf) rkcif_vb_done_oneframe(stream, vb_done); - - cif_dev->buf_wake_up_cnt += 1; - - rkcif_monitor_reset_event(cif_dev); } else { if (cif_dev->is_start_hdr) { - spin_lock_irqsave(&cif_dev->hdr_lock, lock_flags); if (mipi_id == RKCIF_STREAM_MIPI_ID0) { if (cif_dev->rdbk_buf[RDBK_L]) { @@ -4069,7 +4139,6 @@ static void rkcif_update_stream(struct rkcif_device *cif_dev, rkcif_rdbk_frame_end(stream); } spin_unlock_irqrestore(&cif_dev->hdr_lock, lock_flags); - } else { if (active_buf) { vb_done->vb2_buf.state = VB2_BUF_STATE_ACTIVE; @@ -4106,7 +4175,7 @@ u32 rkcif_get_sof(struct rkcif_device *cif_dev) } static int rkcif_do_reset_work(struct rkcif_device *cif_dev, - enum rkcif_reset_src reset_src) + enum rkmodule_reset_src reset_src) { struct rkcif_pipeline *p = &cif_dev->pipe; struct rkcif_stream *stream = NULL; @@ -4139,7 +4208,7 @@ static int rkcif_do_reset_work(struct rkcif_device *cif_dev, } if (stream->id == RKCIF_STREAM_MIPI_ID0) - resume_info->frm_sync_seq = rkcif_csi2_get_sof() + 1; + resume_info->frm_sync_seq = rkcif_get_sof(cif_dev) + 1; stream->state = RKCIF_STATE_RESET_IN_STREAMING; resume_stream[j] = stream; @@ -4159,8 +4228,11 @@ 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_HOTPLUG) + continue; + if (reset_src == RKCIF_RESET_SRC_ERR_CSI2 || - reset_src == RKCIF_RESET_SRC_NORMAL) { + reset_src == RKICF_RESET_SRC_ERR_CUTOFF) { ret = v4l2_subdev_call(p->subdevs[i], core, ioctl, RKMODULE_SET_QUICK_STREAM, &on); @@ -4215,8 +4287,11 @@ static int rkcif_do_reset_work(struct rkcif_device *cif_dev, rkcif_csi2_set_sof(resume_info->frm_sync_seq); + if (reset_src == RKCIF_RESET_SRC_ERR_HOTPLUG) + continue; + if (reset_src == RKCIF_RESET_SRC_ERR_CSI2 || - reset_src == RKCIF_RESET_SRC_NORMAL) { + reset_src == RKICF_RESET_SRC_ERR_CUTOFF) { ret = v4l2_subdev_call(p->subdevs[i], core, ioctl, RKMODULE_SET_QUICK_STREAM, &on); if (ret) @@ -4260,12 +4335,112 @@ static void rkcif_reset_work(struct work_struct *work) } +static bool rkcif_is_reduced_frame_rate(struct rkcif_device *dev) +{ + struct rkcif_timer *timer = &dev->reset_watchdog_timer; + struct rkcif_stream *stream = &dev->stream[RKCIF_STREAM_MIPI_ID0]; + struct v4l2_rect *raw_rect = &dev->terminal_sensor.raw_rect; + u64 fps, timestamp0, timestamp1, diff_time; + unsigned long fps_flags = 0; + unsigned int deviation = 1; + bool is_reduced = false; + + 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); + diff_time = fps > timer->frame_end_cycle_us ? + fps - timer->frame_end_cycle_us : 0; + deviation = DIV_ROUND_UP(timer->vts, 100); + + 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); + + if (diff_time > timer->line_end_cycle * deviation) { + s32 vblank = 0; + unsigned int vts; + + is_reduced = true; + vblank = rkcif_get_sensor_vblank(dev); + vts = vblank + timer->raw_height; + + v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "old vts:%d,new vts:%d\n", timer->vts, vts); + + v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, + "reduce frame rate,vblank:%d, height(raw output):%d, fps:%lld, frm_end_t:%ld, line_t:%ld, diff:%lld\n", + rkcif_get_sensor_vblank(dev), + raw_rect->height, + fps, + timer->frame_end_cycle_us, + timer->line_end_cycle, + diff_time); + + timer->vts = vts; + timer->frame_end_cycle_us = fps; + timer->line_end_cycle = div_u64(timer->frame_end_cycle_us, timer->vts); + } else { + is_reduced = false; + } + + timer->frame_end_cycle_us = fps; + + fps = div_u64(fps, 1000); + fps = fps * timer->frm_num_of_monitor_cycle; + timer->cycle = msecs_to_jiffies(fps); + timer->timer.expires = jiffies + timer->cycle; + + return is_reduced; + +} + +static void rkcif_init_reset_work(struct rkcif_timer *timer) +{ + struct rkcif_device *dev = container_of(timer, + struct rkcif_device, + reset_watchdog_timer); + unsigned long lock_flags = 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, lock_flags); + 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; + spin_unlock_irqrestore(&timer->timer_lock, lock_flags); + + dev->reset_work.reset_src = timer->reset_src; + INIT_WORK(&dev->reset_work.work, rkcif_reset_work); + if (schedule_work_on(smp_processor_id(), &dev->reset_work.work)) + v4l2_err(&dev->v4l2_dev, + "schedule reset work successfully\n"); + else + v4l2_err(&dev->v4l2_dev, + "schedule reset work failed\n"); + +} + 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_device *dev = container_of(timer, + struct rkcif_device, + reset_watchdog_timer); + struct rkcif_sensor_info *terminal_sensor = &dev->terminal_sensor; + unsigned long lock_flags = 0; unsigned int i, stream_num = 1; + int ret, is_reset = 0; + struct rkmodule_vicap_reset_info rst_info; if (dev->hdr.mode == NO_HDR) { i = 0; @@ -4287,13 +4462,46 @@ void rkcif_reset_watchdog_timer_handler(struct timer_list *t) if (timer->last_buf_wakeup_cnt < dev->buf_wake_up_cnt) { - v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "info: frame end still update(%d, %d) in detecting cnt:%d, src:%d\n", - timer->last_buf_wakeup_cnt, dev->buf_wake_up_cnt, - timer->run_cnt, timer->reset_src); + 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->run_cnt, timer->monitor_mode); timer->last_buf_wakeup_cnt = dev->buf_wake_up_cnt; - if (timer->reset_src == RKCIF_RESET_SRC_NORMAL) { + rkcif_is_reduced_frame_rate(dev); + + if (timer->monitor_mode == RKCIF_MONITOR_MODE_HOTPLUG) { + ret = v4l2_subdev_call(terminal_sensor->sd, + core, ioctl, + RKMODULE_GET_VICAP_RST_INFO, + &rst_info); + if (ret) + is_reset = 0; + else + is_reset = rst_info.is_reset; + rst_info.is_reset = 0; + 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) + is_reset = rkcif_is_csi2_err_trigger_reset(timer); + } 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) { + is_reset = timer->is_csi2_err_occurred; + if (is_reset) + timer->reset_src = RKCIF_RESET_SRC_ERR_CSI2; + timer->is_csi2_err_occurred = false; + } + + if (is_reset) { + rkcif_init_reset_work(timer); + return; + } + + 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); @@ -4310,41 +4518,19 @@ void rkcif_reset_watchdog_timer_handler(struct timer_list *t) } } else if (timer->last_buf_wakeup_cnt == dev->buf_wake_up_cnt) { - if (!timer->is_buf_stop_update) { - timer->stop_index_of_run_cnt = timer->run_cnt; - timer->is_buf_stop_update = true; + bool is_reduced = rkcif_is_reduced_frame_rate(dev); + + if (is_reduced) { mod_timer(&timer->timer, jiffies + timer->cycle); - - v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "find first frame end no update(%d, %d) in detecting cnt:%d!\n", - timer->last_buf_wakeup_cnt, dev->buf_wake_up_cnt, timer->run_cnt); - - return; - } - - if ((timer->run_cnt - timer->stop_index_of_run_cnt >= CIF_TIMEOUT_FRAME_NUM) && - timer->is_buf_stop_update) { - - v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, - "do reset work schedule, run_cnt:%d, csi_crc_cnt:%d\n", - timer->run_cnt, timer->csi_crc_cnt); - - spin_lock_irqsave(&timer->timer_lock, lock_flags); - timer->is_triggered = false; - timer->is_running = false; - spin_unlock_irqrestore(&timer->timer_lock, lock_flags); - - dev->reset_work.reset_src = timer->reset_src; - INIT_WORK(&dev->reset_work.work, rkcif_reset_work); - if (schedule_work_on(smp_processor_id(), &dev->reset_work.work)) - v4l2_err(&dev->v4l2_dev, - "schedule reset work successfully,reset src:%d\n", - dev->reset_work.reset_src); - else - v4l2_err(&dev->v4l2_dev, - "schedule reset work failed,reset src:%d\n", - dev->reset_work.reset_src); + v4l2_info(&dev->v4l2_dev, "%s fps is reduced\n", __func__); } else { - mod_timer(&timer->timer, jiffies + timer->cycle); + + v4l2_info(&dev->v4l2_dev, + "do reset work due to frame end is stopped, run_cnt:%d\n", + timer->run_cnt); + + timer->reset_src = RKICF_RESET_SRC_ERR_CUTOFF; + rkcif_init_reset_work(timer); } } @@ -4364,12 +4550,24 @@ end_detect: int rkcif_reset_notifier(struct notifier_block *nb, unsigned long action, void *data) { - struct rkcif_device *dev = container_of(nb, struct rkcif_device, reset_notifier); struct rkcif_timer *timer = &dev->reset_watchdog_timer; + unsigned long lock_flags = 0, val; - timer->csi_crc_cnt = action; - /* TODO: trigger reset work */ + if (timer->is_running) { + val = action & CSI2_ERR_COUNT_ALL_MASK; + spin_lock_irqsave(&timer->csi2_err_lock, lock_flags); + if ((val % timer->csi2_err_ref_cnt) == 0) { + timer->notifer_called_cnt++; + if ((timer->notifer_called_cnt % 2) == 0) + timer->csi2_err_cnt_even = val; + else + timer->csi2_err_cnt_odd = val; + } + + timer->csi2_err_fs_fe_cnt = (action & CSI2_ERR_FSFE_MASK) >> 8; + spin_unlock_irqrestore(&timer->csi2_err_lock, lock_flags); + } return 0; } @@ -4478,6 +4676,7 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev) } rkcif_update_stream(cif_dev, stream, mipi_id); + rkcif_monitor_reset_event(cif_dev); } cif_dev->irq_stats.all_frm_end_cnt++; } else { @@ -4495,7 +4694,7 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev) stream = &cif_dev->stream[RKCIF_STREAM_CIF]; - if ((intstat & LINE_INT_END) && !(intstat & FRAME_END)) { + if ((intstat & LINE_INT_END) && !(intstat & (FRAME_END))) { rkcif_dvp_event_inc_sof(cif_dev); rkcif_write_register(cif_dev, CIF_REG_DVP_INTSTAT, intstat); int_en = rkcif_read_register(cif_dev, CIF_REG_DVP_INTEN); @@ -4589,20 +4788,19 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev) 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); - - spin_lock(&stream->fps_lock); - if (stream->frame_phase & CIF_CSI_FRAME0_READY) - stream->fps_stats.frm0_timestamp = vb_done->vb2_buf.timestamp; - else if (stream->frame_phase & CIF_CSI_FRAME1_READY) - stream->fps_stats.frm1_timestamp = vb_done->vb2_buf.timestamp; - spin_unlock(&stream->fps_lock); } stream->frame_idx++; @@ -4698,6 +4896,7 @@ void rkcif_irq_lite_lvds(struct rkcif_device *cif_dev) } rkcif_update_stream(cif_dev, stream, mipi_id); + rkcif_monitor_reset_event(cif_dev); } 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 602471216299..8e3d245003d0 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -826,6 +826,95 @@ 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; + } + + timer->is_running = false; + timer->is_triggered = false; + timer->is_buf_stop_update = false; + timer->csi2_err_cnt_even = 0; + timer->csi2_err_cnt_odd = 0; + timer->csi2_err_fs_fe_cnt = 0; + timer->csi2_err_fs_fe_detect_cnt = 0; + + timer_setup(&timer->timer, rkcif_reset_watchdog_timer_handler, 0); + + notifier->priority = 1; + notifier->notifier_call = rkcif_reset_notifier; + rkcif_csi2_register_notifier(notifier); + +} + int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int inf_id) { struct device *dev = cif_dev->dev; @@ -838,6 +927,7 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int mutex_init(&cif_dev->stream_lock); spin_lock_init(&cif_dev->hdr_lock); spin_lock_init(&cif_dev->reset_watchdog_timer.timer_lock); + spin_lock_init(&cif_dev->reset_watchdog_timer.csi2_err_lock); atomic_set(&cif_dev->pipe.power_cnt, 0); atomic_set(&cif_dev->pipe.stream_cnt, 0); atomic_set(&cif_dev->fh_cnt, 0); @@ -998,16 +1088,7 @@ static int rkcif_plat_probe(struct platform_device *pdev) if (rkcif_proc_init(cif_dev)) dev_warn(dev, "dev:%s create proc failed\n", dev_name(dev)); - cif_dev->reset_notifier.priority = 1; - cif_dev->reset_notifier.notifier_call = rkcif_reset_notifier; - rkcif_csi2_register_notifier(&cif_dev->reset_notifier); -#if defined(CONFIG_ROCKCHIP_CIF_RESET_MONITOR_CONTINU) - cif_dev->reset_watchdog_timer.reset_src = RKCIF_RESET_SRC_NORMAL; -#else - cif_dev->reset_watchdog_timer.reset_src = RKCIF_RESET_SRC_NON; -#endif - timer_setup(&cif_dev->reset_watchdog_timer.timer, - rkcif_reset_watchdog_timer_handler, 0); + rkcif_init_reset_monitor(cif_dev); rkcif_soft_reset(cif_dev, true); pm_runtime_enable(&pdev->dev); diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index 1109caa20eab..0bc3995ffb3e 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -28,6 +28,9 @@ #define CIF_DRIVER_NAME "rkcif" #define CIF_VIDEODEVICE_NAME "stream_cif" +#define OF_CIF_MONITOR_PARA "rockchip,cif-monitor" +#define CIF_MONITOR_PARA_NUM (5) + #define RKCIF_SINGLE_STREAM 1 #define RKCIF_STREAM_CIF 0 #define CIF_DVP_VDEV_NAME CIF_VIDEODEVICE_NAME "_dvp" @@ -301,14 +304,14 @@ struct rkcif_irq_stats { }; /* - * the causation to do cif reset work + * the detecting mode of cif reset timer + * related with dts property:rockchip,cif-monitor */ -enum rkcif_reset_src { - RKCIF_RESET_SRC_NON = 0x0, - RKCIF_RESET_SRC_NORMAL, - RKCIF_RESET_SRC_ERR_CSI2, - RKCIF_RESET_SRC_ERR_LVDS, - RKCIF_RESET_SRC_ERR_APP, +enum rkcif_monitor_mode { + RKCIF_MONITOR_MODE_IDLE = 0x0, + RKCIF_MONITOR_MODE_CONTINUE, + RKCIF_MONITOR_MODE_TRIGGER, + RKCIF_MONITOR_MODE_HOTPLUG, }; /* @@ -320,23 +323,40 @@ struct rkcif_resume_info { struct rkcif_work_struct { struct work_struct work; - enum rkcif_reset_src reset_src; + enum rkmodule_reset_src reset_src; struct rkcif_resume_info resume_info; }; struct rkcif_timer { struct timer_list timer; spinlock_t timer_lock; + spinlock_t csi2_err_lock; unsigned long cycle; + /* unit: us */ + unsigned long line_end_cycle; unsigned int run_cnt; unsigned int max_run_cnt; unsigned int stop_index_of_run_cnt; unsigned int last_buf_wakeup_cnt; - unsigned int csi_crc_cnt; + unsigned long csi2_err_cnt_even; + unsigned long csi2_err_cnt_odd; + unsigned int csi2_err_ref_cnt; + unsigned int csi2_err_fs_fe_cnt; + unsigned int csi2_err_fs_fe_detect_cnt; + unsigned int frm_num_of_monitor_cycle; + unsigned int triggered_frame_num; + unsigned int vts; + unsigned int raw_height; + /* unit: ms */ + unsigned int err_time_interval; + unsigned long frame_end_cycle_us; + unsigned int notifer_called_cnt; bool is_triggered; bool is_buf_stop_update; bool is_running; - enum rkcif_reset_src reset_src; + bool is_csi2_err_occurred; + enum rkcif_monitor_mode monitor_mode; + enum rkmodule_reset_src reset_src; }; struct rkcif_extend_info { diff --git a/drivers/media/platform/rockchip/cif/mipi-csi2.c b/drivers/media/platform/rockchip/cif/mipi-csi2.c index 786136e9f03b..176b46794b45 100644 --- a/drivers/media/platform/rockchip/cif/mipi-csi2.c +++ b/drivers/media/platform/rockchip/cif/mipi-csi2.c @@ -70,7 +70,12 @@ enum csi2_pads { }; enum csi2_err { - RK_CSI2_ERR_CRC = 0, + RK_CSI2_ERR_SOTSYN = 0x0, + RK_CSI2_ERR_FS_FE_MIS, + RK_CSI2_ERR_FRM_SEQ_ERR, + RK_CSI2_ERR_CRC_ONCE, + RK_CSI2_ERR_CRC, + RK_CSI2_ERR_ALL, RK_CSI2_ERR_MAX }; @@ -680,7 +685,8 @@ static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx) { struct device *dev = ctx; struct csi2_dev *csi2 = sd_to_dev(dev_get_drvdata(dev)); - struct csi2_err_stats *err_stats = NULL; + struct csi2_err_stats *err_list = NULL; + unsigned long err_stat = 0; u32 val; val = read_csihost_reg(csi2->base, CSIHOST_ERR1); @@ -688,35 +694,53 @@ static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx) write_csihost_reg(csi2->base, CSIHOST_ERR1, 0x0); - if (val & CSIHOST_ERR1_PHYERR_SPTSYNCHS) + if (val & CSIHOST_ERR1_PHYERR_SPTSYNCHS) { + err_list = &csi2->err_list[RK_CSI2_ERR_SOTSYN]; + err_list->cnt++; v4l2_err(&csi2->sd, - "ERR1: start of transmission error(no synchronization achieved), reg: 0x%x\n", - val); + "ERR1: start of transmission error(no synchronization achieved), reg: 0x%x,cnt:%d\n", + val, err_list->cnt); + } - if (val & CSIHOST_ERR1_ERR_BNDRY_MATCH) + if (val & CSIHOST_ERR1_ERR_BNDRY_MATCH) { + err_list = &csi2->err_list[RK_CSI2_ERR_FS_FE_MIS]; + err_list->cnt++; v4l2_err(&csi2->sd, - "ERR1: error matching frame start with frame end, reg: 0x%x\n", - val); + "ERR1: error matching frame start with frame end, reg: 0x%x,cnt:%d\n", + val, err_list->cnt); + } - if (val & CSIHOST_ERR1_ERR_SEQ) + if (val & CSIHOST_ERR1_ERR_SEQ) { + err_list = &csi2->err_list[RK_CSI2_ERR_FRM_SEQ_ERR]; + err_list->cnt++; v4l2_err(&csi2->sd, - "ERR1: incorrect frame sequence detected, reg: 0x%x\n", - val); + "ERR1: incorrect frame sequence detected, reg: 0x%x,cnt:%d\n", + val, err_list->cnt); + } - if (val & CSIHOST_ERR1_ERR_FRM_DATA) + if (val & CSIHOST_ERR1_ERR_FRM_DATA) { + err_list = &csi2->err_list[RK_CSI2_ERR_CRC_ONCE]; + err_list->cnt++; v4l2_dbg(1, csi2_debug, &csi2->sd, - "ERR1: at least one crc error, reg: 0x%x\n", val); + "ERR1: at least one crc error, reg: 0x%x\n,cnt:%d", val, err_list->cnt); + } if (val & CSIHOST_ERR1_ERR_CRC) { - - err_stats = &csi2->err_list[RK_CSI2_ERR_CRC]; - err_stats->cnt += 1; - atomic_notifier_call_chain(&g_csi_host_chain, err_stats->cnt, NULL); - + err_list = &csi2->err_list[RK_CSI2_ERR_CRC]; + err_list->cnt++; v4l2_err(&csi2->sd, "ERR1: crc errors, reg: 0x%x, cnt:%d\n", - val, err_stats->cnt); + val, err_list->cnt); } + + csi2->err_list[RK_CSI2_ERR_ALL].cnt++; + err_stat = ((csi2->err_list[RK_CSI2_ERR_FS_FE_MIS].cnt & 0xff) << 8) | + ((csi2->err_list[RK_CSI2_ERR_ALL].cnt) & 0xff); + + atomic_notifier_call_chain(&g_csi_host_chain, + err_stat, + NULL); + } return IRQ_HANDLED; diff --git a/drivers/media/platform/rockchip/cif/mipi-csi2.h b/drivers/media/platform/rockchip/cif/mipi-csi2.h index f0f4a633d0ea..cfa52e29dbe2 100644 --- a/drivers/media/platform/rockchip/cif/mipi-csi2.h +++ b/drivers/media/platform/rockchip/cif/mipi-csi2.h @@ -5,6 +5,9 @@ #include +#define CSI2_ERR_FSFE_MASK (0xff << 8) +#define CSI2_ERR_COUNT_ALL_MASK (0xff) + u32 rkcif_csi2_get_sof(void); void rkcif_csi2_set_sof(u32 seq); void rkcif_csi2_event_inc_sof(void); diff --git a/drivers/media/platform/rockchip/cif/procfs.c b/drivers/media/platform/rockchip/cif/procfs.c index 495d9efcd36f..e9f86e8abc21 100644 --- a/drivers/media/platform/rockchip/cif/procfs.c +++ b/drivers/media/platform/rockchip/cif/procfs.c @@ -196,8 +196,26 @@ static const char *rkcif_pixelcode_to_string(u32 mbus_code) return "unknown"; } +static const char *rkcif_get_monitor_mode(enum rkcif_monitor_mode monitor_mode) +{ + switch (monitor_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_show_mixed_info(struct rkcif_device *dev, struct seq_file *f) { + enum rkcif_monitor_mode monitor_mode; + seq_printf(f, "Driver Version:v%02x.%02x.%02x\n", RKCIF_DRIVER_VERSION >> 16, (RKCIF_DRIVER_VERSION & 0xff00) >> 8, @@ -205,6 +223,10 @@ static void rkcif_show_mixed_info(struct rkcif_device *dev, struct seq_file *f) seq_printf(f, "Work Mode:%s\n", dev->workmode == RKCIF_WORKMODE_ONEFRAME ? "one frame" : dev->workmode == RKCIF_WORKMODE_PINGPONG ? "ping pong" : "line loop"); + + monitor_mode = dev->reset_watchdog_timer.monitor_mode; + seq_printf(f, "Monitor Mode:%s\n", + rkcif_get_monitor_mode(monitor_mode)); } static void rkcif_show_clks(struct rkcif_device *dev, struct seq_file *f) diff --git a/drivers/media/platform/rockchip/cif/regs.h b/drivers/media/platform/rockchip/cif/regs.h index 7ec2a592e7e2..8cf56b10e2c8 100644 --- a/drivers/media/platform/rockchip/cif/regs.h +++ b/drivers/media/platform/rockchip/cif/regs.h @@ -322,9 +322,11 @@ enum cif_reg_index { #define IFIFO_OVERFLOW (0x1 << 4) #define DFIFO_OVERFLOW (0x1 << 5) #define BUS_ERR (0x1 << 6) +#define PRE_INF_FRAME_END (0x01 << 8) #define PST_INF_FRAME_END (0x01 << 9) #define LINE_INT_END (0x1 << 10) #define FRAME_END_CLR (0x01 << 0) +#define PRE_INF_FRAME_END_CLR (0x01 << 8) #define PST_INF_FRAME_END_CLR (0x01 << 9) #define INTSTAT_ERR (0xFC) #define DVP_ALL_OVERFLOW (IFIFO_OVERFLOW | DFIFO_OVERFLOW) diff --git a/drivers/media/platform/rockchip/cif/version.h b/drivers/media/platform/rockchip/cif/version.h index f893a6b9aa09..569cb2c3bbd9 100644 --- a/drivers/media/platform/rockchip/cif/version.h +++ b/drivers/media/platform/rockchip/cif/version.h @@ -54,6 +54,7 @@ *2. support rk3568 csi-host *3. add dvp sof *4. add extended lines to out image for normal & hdr short frame + *5. modify reset mechanism drivered by real-time frame rate */ #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 2b554eb0bc09..ee947fd0373e 100644 --- a/include/uapi/linux/rk-camera-module.h +++ b/include/uapi/linux/rk-camera-module.h @@ -69,6 +69,12 @@ #define RKMODULE_GET_START_STREAM_SEQ \ _IOR('V', BASE_VIDIOC_PRIVATE + 14, __u32) +#define RKMODULE_GET_VICAP_RST_INFO \ + _IOR('V', BASE_VIDIOC_PRIVATE + 15, struct rkmodule_vicap_reset_info) + +#define RKMODULE_SET_VICAP_RST_INFO \ + _IOR('V', BASE_VIDIOC_PRIVATE + 16, struct rkmodule_vicap_reset_info) + /** * struct rkmodule_base_inf - module base information * @@ -370,4 +376,21 @@ enum rkmodule_start_stream_seq { RKMODULE_START_STREAM_FRONT, }; +/* + * the causation to do cif reset work + */ +enum rkmodule_reset_src { + RKCIF_RESET_SRC_NON = 0x0, + RKCIF_RESET_SRC_ERR_CSI2, + RKCIF_RESET_SRC_ERR_LVDS, + RKICF_RESET_SRC_ERR_CUTOFF, + RKCIF_RESET_SRC_ERR_HOTPLUG, + RKCIF_RESET_SRC_ERR_APP, +}; + +struct rkmodule_vicap_reset_info { + __u32 is_reset; + enum rkmodule_reset_src src; +} __attribute__ ((packed)); + #endif /* _UAPI_RKMODULE_CAMERA_H */