media: rockchip: vicap supports anomaly detection

Signed-off-by: Zefa Chen <zefa.chen@rock-chips.com>
Change-Id: I205c9673f7f567597ec3c9e42d5cec1a58b87f5b
This commit is contained in:
Zefa Chen
2022-06-06 16:31:12 +08:00
parent f1082a51d0
commit 8704b56415
7 changed files with 320 additions and 203 deletions

View File

@@ -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.

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -66,6 +66,7 @@ struct rkcif_multi_sync_config {
u32 sync_mask;
u32 update_code;
u32 update_cache;
u32 frame_idx;
bool is_attach;
};

View File

@@ -18,6 +18,7 @@
#include <linux/rk-camera-module.h>
#include <media/v4l2-ioctl.h>
#include "mipi-csi2.h"
#include <linux/rkcif-config.h>
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)

View File

@@ -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