media: rockchip: cif: mipi wakes up buf by line int

Signed-off-by: Zefa Chen <zefa.chen@rock-chips.com>
Change-Id: If10afeec22ce89a52f7c0e0e454005ca3c3cdc5e
This commit is contained in:
Zefa Chen
2021-07-05 17:39:39 +08:00
parent 17f00b1208
commit 454228fa8d
5 changed files with 458 additions and 115 deletions

View File

@@ -1107,9 +1107,10 @@ static int rkcif_assign_new_buffer_oneframe(struct rkcif_stream *stream,
struct rkcif_buffer *buffer = NULL;
u32 frm_addr_y = CIF_REG_DVP_FRM0_ADDR_Y;
u32 frm_addr_uv = CIF_REG_DVP_FRM0_ADDR_UV;
unsigned long flags;
int ret = 0;
spin_lock(&stream->vbq_lock);
spin_lock_irqsave(&stream->vbq_lock, flags);
if (stat == RKCIF_YUV_ADDR_STATE_INIT) {
if (!stream->curr_buf) {
if (!list_empty(&stream->buf_head)) {
@@ -1157,7 +1158,6 @@ static int rkcif_assign_new_buffer_oneframe(struct rkcif_stream *stream,
} else {
buffer = NULL;
}
if (stream->frame_phase == CIF_CSI_FRAME0_READY) {
frm_addr_y = CIF_REG_DVP_FRM0_ADDR_Y;
frm_addr_uv = CIF_REG_DVP_FRM0_ADDR_UV;
@@ -1177,7 +1177,7 @@ static int rkcif_assign_new_buffer_oneframe(struct rkcif_stream *stream,
"not active buffer, frame Drop\n");
}
}
spin_unlock(&stream->vbq_lock);
spin_unlock_irqrestore(&stream->vbq_lock, flags);
return ret;
}
@@ -1188,6 +1188,7 @@ static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream,
struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus;
u32 frm0_addr_y, frm0_addr_uv;
u32 frm1_addr_y, frm1_addr_uv;
unsigned long flags;
if (mbus_cfg->type == V4L2_MBUS_CSI2 ||
mbus_cfg->type == V4L2_MBUS_CCP2) {
@@ -1202,7 +1203,7 @@ static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream,
frm1_addr_uv = get_dvp_reg_index_of_frm1_uv_addr(channel_id);
}
spin_lock(&stream->vbq_lock);
spin_lock_irqsave(&stream->vbq_lock, flags);
if (!stream->curr_buf) {
if (!list_empty(&stream->buf_head)) {
@@ -1236,6 +1237,7 @@ static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream,
rkcif_write_register(dev, frm1_addr_uv,
stream->next_buf->buff_addr[RKCIF_PLANE_CBCR]);
}
spin_unlock_irqrestore(&stream->vbq_lock, flags);
stream->is_dvp_yuv_addr_init = true;
@@ -1267,7 +1269,6 @@ static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream,
}
}
spin_unlock(&stream->vbq_lock);
}
static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream,
@@ -1278,6 +1279,7 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream,
struct rkcif_buffer *buffer = NULL;
u32 frm_addr_y, frm_addr_uv;
int ret = 0;
unsigned long flags;
if (mbus_cfg->type == V4L2_MBUS_CSI2 ||
mbus_cfg->type == V4L2_MBUS_CCP2) {
@@ -1296,7 +1298,7 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream,
get_dvp_reg_index_of_frm1_uv_addr(channel_id);
}
spin_lock(&stream->vbq_lock);
spin_lock_irqsave(&stream->vbq_lock, flags);
if (!list_empty(&stream->buf_head)) {
if (stream->frame_phase == CIF_CSI_FRAME0_READY) {
stream->curr_buf = list_first_entry(&stream->buf_head,
@@ -1316,7 +1318,85 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream,
} else {
buffer = NULL;
}
spin_unlock(&stream->vbq_lock);
spin_unlock_irqrestore(&stream->vbq_lock, flags);
if (buffer) {
rkcif_write_register(dev, frm_addr_y,
buffer->buff_addr[RKCIF_PLANE_Y]);
if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW)
rkcif_write_register(dev, frm_addr_uv,
buffer->buff_addr[RKCIF_PLANE_CBCR]);
} else {
ret = -EINVAL;
v4l2_info(&dev->v4l2_dev,
"not active buffer, skip current frame, %s stream[%d]\n",
(mbus_cfg->type == V4L2_MBUS_CSI2 ||
mbus_cfg->type == V4L2_MBUS_CCP2) ? "mipi/lvds" : "dvp",
stream->id);
}
return ret;
}
static int rkcif_get_new_buffer_wake_up_mode(struct rkcif_stream *stream)
{
int ret = 0;
unsigned long flags = 0;
spin_lock_irqsave(&stream->vbq_lock, flags);
if (!list_empty(&stream->buf_head)) {
if (stream->line_int_cnt % 2) {
stream->curr_buf = list_first_entry(&stream->buf_head,
struct rkcif_buffer, queue);
if (stream->curr_buf)
list_del(&stream->curr_buf->queue);
} else {
stream->next_buf = list_first_entry(&stream->buf_head,
struct rkcif_buffer, queue);
if (stream->next_buf)
list_del(&stream->next_buf->queue);
}
stream->is_buf_active = true;
} else {
ret = -EINVAL;
stream->is_buf_active = false;
}
spin_unlock_irqrestore(&stream->vbq_lock, flags);
return ret;
}
static int rkcif_update_new_buffer_wake_up_mode(struct rkcif_stream *stream)
{
struct rkcif_device *dev = stream->cifdev;
struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus;
struct rkcif_buffer *buffer = NULL;
u32 frm_addr_y, frm_addr_uv;
int channel_id = stream->id;
int ret = 0;
if (mbus_cfg->type == V4L2_MBUS_CSI2 ||
mbus_cfg->type == V4L2_MBUS_CCP2) {
frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ?
get_reg_index_of_frm0_y_addr(channel_id) :
get_reg_index_of_frm1_y_addr(channel_id);
frm_addr_uv = stream->frame_phase & CIF_CSI_FRAME0_READY ?
get_reg_index_of_frm0_uv_addr(channel_id) :
get_reg_index_of_frm1_uv_addr(channel_id);
} else {
frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ?
get_dvp_reg_index_of_frm0_y_addr(channel_id) :
get_dvp_reg_index_of_frm1_y_addr(channel_id);
frm_addr_uv = stream->frame_phase & CIF_CSI_FRAME0_READY ?
get_dvp_reg_index_of_frm0_uv_addr(channel_id) :
get_dvp_reg_index_of_frm1_uv_addr(channel_id);
}
if (stream->is_buf_active) {
if (stream->frame_phase == CIF_CSI_FRAME0_READY)
buffer = stream->curr_buf;
else if (stream->frame_phase == CIF_CSI_FRAME1_READY)
buffer = stream->next_buf;
}
if (buffer) {
rkcif_write_register(dev, frm_addr_y,
@@ -1526,6 +1606,8 @@ static int rkcif_csi_channel_set(struct rkcif_stream *stream,
{
unsigned int val = 0x0;
struct rkcif_device *dev = stream->cifdev;
struct rkcif_stream *detect_stream = &dev->stream[0];
unsigned int wait_line = 0x3fff;
if (channel->id >= 4)
return -EINVAL;
@@ -1545,15 +1627,18 @@ static int rkcif_csi_channel_set(struct rkcif_stream *stream,
if (channel->id == RKCIF_STREAM_MIPI_ID0)
rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN,
CSI_START_INTEN(channel->id));
if (detect_stream->is_line_wake_up) {
rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN,
CSI_LINE_INTEN(channel->id));
wait_line = dev->wait_line;
}
rkcif_write_register(dev, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1,
0x3fff << 16 | 0x3fff);
wait_line << 16 | wait_line);
rkcif_write_register(dev, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3,
0x3fff << 16 | 0x3fff);
wait_line << 16 | wait_line);
rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN,
CSI_DMA_END_INTEN(channel->id));
rkcif_write_register(dev, CIF_REG_MIPI_WATER_LINE,
CIF_MIPI_LVDS_SW_WATER_LINE_25_RK1808 |
CIF_MIPI_LVDS_SW_WATER_LINE_ENABLE_RK1808 |
@@ -1669,6 +1754,11 @@ static int rkcif_csi_stream_start(struct rkcif_stream *stream)
rkcif_csi_channel_set(stream, channel, V4L2_MBUS_CCP2);
}
stream->line_int_cnt = 0;
if (stream->is_line_wake_up)
stream->is_can_stop = false;
else
stream->is_can_stop = true;
stream->state = RKCIF_STATE_STREAMING;
dev->workmode = RKCIF_WORKMODE_PINGPONG;
@@ -1813,7 +1903,7 @@ static void rkcif_buf_queue(struct vb2_buffer *vb)
struct v4l2_pix_format_mplane *pixm = &stream->pixm;
const struct cif_output_fmt *fmt = stream->cif_fmt_out;
struct rkcif_hw *hw_dev = stream->cifdev->hw_dev;
unsigned long lock_flags = 0;
unsigned long flags;
int i;
memset(cifbuf->buff_addr, 0, sizeof(cifbuf->buff_addr));
@@ -1843,10 +1933,9 @@ static void rkcif_buf_queue(struct vb2_buffer *vb)
cifbuf->buff_addr[i + 1] = cifbuf->buff_addr[i] +
pixm->plane_fmt[i].bytesperline * pixm->height;
}
spin_lock_irqsave(&stream->vbq_lock, lock_flags);
spin_lock_irqsave(&stream->vbq_lock, flags);
list_add_tail(&cifbuf->queue, &stream->buf_head);
spin_unlock_irqrestore(&stream->vbq_lock, lock_flags);
spin_unlock_irqrestore(&stream->vbq_lock, flags);
}
static void rkcif_do_cru_reset(struct rkcif_device *dev)
@@ -1897,7 +1986,7 @@ static void rkcif_release_rdbk_buf(struct rkcif_stream *stream)
struct rkcif_device *dev = stream->cifdev;
struct rkcif_buffer *rdbk_buf;
struct rkcif_buffer *tmp_buf;
unsigned long lock_flags = 0;
unsigned long flags;
bool has_added;
int index = 0;
@@ -1910,7 +1999,7 @@ static void rkcif_release_rdbk_buf(struct rkcif_stream *stream)
else
return;
spin_lock_irqsave(&dev->hdr_lock, lock_flags);
spin_lock_irqsave(&dev->hdr_lock, flags);
rdbk_buf = dev->rdbk_buf[index];
if (rdbk_buf) {
if (rdbk_buf != stream->curr_buf &&
@@ -1930,7 +2019,7 @@ static void rkcif_release_rdbk_buf(struct rkcif_stream *stream)
}
dev->rdbk_buf[index] = NULL;
}
spin_unlock_irqrestore(&dev->hdr_lock, lock_flags);
spin_unlock_irqrestore(&dev->hdr_lock, flags);
}
@@ -2550,6 +2639,8 @@ static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count)
int rkmodule_stream_seq = RKMODULE_START_STREAM_DEFAULT;
int ret;
v4l2_info(&dev->v4l2_dev, "stream[%d] start streaming\n", stream->id);
mutex_lock(&dev->stream_lock);
if (WARN_ON(stream->state != RKCIF_STATE_READY)) {
@@ -2557,7 +2648,10 @@ static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count)
v4l2_err(v4l2_dev, "stream in busy state\n");
goto destroy_buf;
}
if (stream->is_line_wake_up)
stream->is_line_inten = true;
else
stream->is_line_inten = false;
stream->fs_cnt_in_single_frame = 0;
if (dev->active_sensor) {
@@ -2920,6 +3014,15 @@ void rkcif_stream_init(struct rkcif_device *dev, u32 id)
stream->is_dvp_yuv_addr_init = false;
stream->is_fs_fe_not_paired = false;
stream->fs_cnt_in_single_frame = 0;
if (dev->wait_line) {
dev->wait_line_cache = dev->wait_line;
dev->wait_line_bak = dev->wait_line;
stream->is_line_wake_up = true;
} else {
stream->is_line_wake_up = false;
dev->wait_line_cache = 0;
dev->wait_line_bak = 0;
}
}
@@ -3368,8 +3471,7 @@ static int rkcif_s_ctrl(struct file *file, void *fh,
stream->is_compact = true;
else
stream->is_compact = false;
break;
break;
default:
return -EINVAL;
}
@@ -4114,9 +4216,9 @@ static bool rkcif_is_csi2_err_trigger_reset(struct rkcif_timer *timer)
struct rkcif_stream *stream = &dev->stream[RKCIF_STREAM_MIPI_ID0];
bool is_triggered = false;
unsigned long lock_flags;
unsigned long flags;
spin_lock_irqsave(&timer->csi2_err_lock, lock_flags);
spin_lock_irqsave(&timer->csi2_err_lock, flags);
if (timer->csi2_err_cnt_even != 0 &&
timer->csi2_err_cnt_odd != 0) {
@@ -4137,7 +4239,7 @@ static bool rkcif_is_csi2_err_trigger_reset(struct rkcif_timer *timer)
v4l2_info(&dev->v4l2_dev, "reset for fs & fe not paired\n");
}
spin_unlock_irqrestore(&timer->csi2_err_lock, lock_flags);
spin_unlock_irqrestore(&timer->csi2_err_lock, flags);
return is_triggered;
}
@@ -4308,7 +4410,7 @@ static void rkcif_monitor_reset_event(struct rkcif_device *dev)
struct rkcif_timer *timer = &dev->reset_watchdog_timer;
unsigned int cycle = 0;
u64 fps, timestamp0, timestamp1;
unsigned long lock_flags = 0, fps_flags = 0;
unsigned long flags, fps_flags;
if (timer->monitor_mode == RKCIF_MONITOR_MODE_IDLE)
return;
@@ -4333,7 +4435,7 @@ static void rkcif_monitor_reset_event(struct rkcif_device *dev)
timestamp1 = stream->fps_stats.frm1_timestamp;
spin_unlock_irqrestore(&stream->fps_lock, fps_flags);
spin_lock_irqsave(&timer->timer_lock, lock_flags);
spin_lock_irqsave(&timer->timer_lock, flags);
fps = timestamp0 > timestamp1 ?
timestamp0 - timestamp1 : timestamp1 - timestamp0;
@@ -4365,7 +4467,7 @@ static void rkcif_monitor_reset_event(struct rkcif_device *dev)
timer->timer.expires = jiffies + timer->cycle;
mod_timer(&timer->timer, timer->timer.expires);
spin_unlock_irqrestore(&timer->timer_lock, lock_flags);
spin_unlock_irqrestore(&timer->timer_lock, flags);
v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev,
"%s:mode:%d, raw height:%d,vblank:%d, cycle:%ld, fps:%llu\n",
@@ -4523,52 +4625,28 @@ RDBK_FRM_UNMATCH:
dev->rdbk_buf[RDBK_S] = NULL;
}
static void rkcif_update_stream(struct rkcif_device *cif_dev,
struct rkcif_stream *stream,
int mipi_id)
static void rkcif_buf_done_prepare(struct rkcif_stream *stream,
struct rkcif_buffer *active_buf,
int mipi_id,
u32 mode)
{
struct rkcif_buffer *active_buf = NULL;
unsigned long flags;
struct vb2_v4l2_buffer *vb_done = NULL;
unsigned long lock_flags = 0;
int ret = 0;
if (stream->frame_phase == (CIF_CSI_FRAME0_READY | CIF_CSI_FRAME1_READY)) {
v4l2_err(&cif_dev->v4l2_dev, "stream[%d], frm0/frm1 end simultaneously,frm id:%d\n",
stream->id, stream->frame_idx);
stream->frame_idx++;
return;
}
spin_lock(&stream->fps_lock);
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();
} else 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();
}
spin_unlock(&stream->fps_lock);
cif_dev->buf_wake_up_cnt += 1;
ret = rkcif_assign_new_buffer_pingpong(stream,
RKCIF_YUV_ADDR_STATE_UPDATE,
mipi_id);
if (ret)
goto end;
if (cif_dev->chip_id == CHIP_RV1126_CIF ||
cif_dev->chip_id == CHIP_RV1126_CIF_LITE ||
cif_dev->chip_id == CHIP_RK3568_CIF)
rkcif_luma_isr(&cif_dev->luma_vdev, mipi_id, stream->frame_idx);
struct rkcif_device *cif_dev = stream->cifdev;
if (active_buf) {
vb_done = &active_buf->vb;
vb_done->vb2_buf.timestamp = ktime_get_ns();
vb_done->sequence = stream->frame_idx;
if (stream->is_line_wake_up) {
spin_lock_irqsave(&stream->fps_lock, flags);
if (mode)
stream->fps_stats.frm0_timestamp = vb_done->vb2_buf.timestamp;
else
stream->fps_stats.frm1_timestamp = vb_done->vb2_buf.timestamp;
stream->readout.wk_timestamp = vb_done->vb2_buf.timestamp;
spin_unlock_irqrestore(&stream->fps_lock, flags);
}
}
if (cif_dev->hdr.mode == NO_HDR) {
@@ -4576,7 +4654,7 @@ static void rkcif_update_stream(struct rkcif_device *cif_dev,
rkcif_vb_done_oneframe(stream, vb_done);
} else {
if (cif_dev->is_start_hdr) {
spin_lock_irqsave(&cif_dev->hdr_lock, lock_flags);
spin_lock_irqsave(&cif_dev->hdr_lock, flags);
if (mipi_id == RKCIF_STREAM_MIPI_ID0) {
if (cif_dev->rdbk_buf[RDBK_L]) {
v4l2_err(&cif_dev->v4l2_dev,
@@ -4616,7 +4694,7 @@ static void rkcif_update_stream(struct rkcif_device *cif_dev,
if (cif_dev->hdr.mode == HDR_X3)
rkcif_rdbk_frame_end(stream);
}
spin_unlock_irqrestore(&cif_dev->hdr_lock, lock_flags);
spin_unlock_irqrestore(&cif_dev->hdr_lock, flags);
} else {
if (active_buf) {
vb_done->vb2_buf.state = VB2_BUF_STATE_ACTIVE;
@@ -4632,8 +4710,123 @@ static void rkcif_update_stream(struct rkcif_device *cif_dev,
cif_dev->stream[3].state != RKCIF_STATE_STREAMING ? "stopped" : "running");
}
}
end:
}
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;
if (mode) {
if (stream->curr_buf)
active_buf = stream->curr_buf;
} else {
if (stream->next_buf)
active_buf = stream->next_buf;
}
if (stream->stopping) {
stream->is_can_stop = true;
return;
}
ret = rkcif_get_new_buffer_wake_up_mode(stream);
if (ret)
goto end_wake_up;
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;
stream->frame_idx++;
}
static void rkcif_deal_readout_time(struct rkcif_stream *stream)
{
struct rkcif_device *cif_dev = stream->cifdev;
struct rkcif_stream *detect_stream = &cif_dev->stream[0];
unsigned long flags;
spin_lock_irqsave(&stream->fps_lock, flags);
stream->readout.fe_timestamp = ktime_get_ns();
if (stream->id == RKCIF_STREAM_MIPI_ID0)
detect_stream->readout.readout_time = stream->readout.fe_timestamp - stream->readout.fs_timestamp;
if ((cif_dev->hdr.mode == NO_HDR) && (stream->id == RKCIF_STREAM_MIPI_ID0)) {
detect_stream->readout.early_time = stream->readout.fe_timestamp - stream->readout.wk_timestamp;
} else if ((cif_dev->hdr.mode == HDR_X2) && (stream->id == RKCIF_STREAM_MIPI_ID1)) {
detect_stream->readout.early_time = stream->readout.fe_timestamp - stream->readout.wk_timestamp;
detect_stream->readout.total_time = stream->readout.fe_timestamp - detect_stream->readout.fs_timestamp;
} else if ((cif_dev->hdr.mode == HDR_X3) && (stream->id == RKCIF_STREAM_MIPI_ID2)) {
detect_stream->readout.early_time = stream->readout.fe_timestamp - stream->readout.wk_timestamp;
detect_stream->readout.total_time = stream->readout.fe_timestamp - detect_stream->readout.fs_timestamp;
}
if (!stream->is_line_wake_up)
detect_stream->readout.early_time = 0;
spin_unlock_irqrestore(&stream->fps_lock, flags);
}
static void rkcif_update_stream(struct rkcif_device *cif_dev,
struct rkcif_stream *stream,
int mipi_id)
{
struct rkcif_buffer *active_buf = NULL;
unsigned long flags;
int ret = 0;
if (stream->frame_phase == (CIF_CSI_FRAME0_READY | CIF_CSI_FRAME1_READY)) {
v4l2_err(&cif_dev->v4l2_dev, "stream[%d], frm0/frm1 end simultaneously,frm id:%d\n",
stream->id, stream->frame_idx);
stream->frame_idx++;
return;
}
if (!stream->is_line_wake_up) {
spin_lock_irqsave(&stream->fps_lock, flags);
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();
} else 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();
}
spin_unlock_irqrestore(&stream->fps_lock, flags);
if (mipi_id == RKCIF_STREAM_MIPI_ID0)
cif_dev->buf_wake_up_cnt += 1;
}
rkcif_deal_readout_time(stream);
if (!stream->is_line_wake_up) {
ret = rkcif_assign_new_buffer_pingpong(stream,
RKCIF_YUV_ADDR_STATE_UPDATE,
mipi_id);
if (ret)
goto end;
} else {
ret = rkcif_update_new_buffer_wake_up_mode(stream);
if (ret)
return;
}
if (cif_dev->chip_id == CHIP_RV1126_CIF ||
cif_dev->chip_id == CHIP_RV1126_CIF_LITE ||
cif_dev->chip_id == CHIP_RK3568_CIF)
rkcif_luma_isr(&cif_dev->luma_vdev, mipi_id, stream->frame_idx);
if (!stream->is_line_wake_up) {
rkcif_buf_done_prepare(stream, active_buf, mipi_id, 0);
end:
stream->frame_idx++;
}
}
u32 rkcif_get_sof(struct rkcif_device *cif_dev)
@@ -4903,7 +5096,7 @@ 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;
unsigned long flags;
if (timer->has_been_init)
return;
@@ -4912,7 +5105,7 @@ static void rkcif_init_reset_work(struct rkcif_timer *timer)
"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);
spin_lock_irqsave(&timer->timer_lock, flags);
timer->is_running = false;
timer->is_triggered = false;
timer->csi2_err_cnt_odd = 0;
@@ -4920,7 +5113,7 @@ static void rkcif_init_reset_work(struct rkcif_timer *timer)
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);
spin_unlock_irqrestore(&timer->timer_lock, flags);
dev->reset_work.reset_src = timer->reset_src;
if (schedule_work(&dev->reset_work.work)) {
@@ -4941,7 +5134,7 @@ void rkcif_reset_watchdog_timer_handler(struct timer_list *t)
reset_watchdog_timer);
struct rkcif_sensor_info *terminal_sensor = &dev->terminal_sensor;
unsigned long lock_flags = 0;
unsigned long flags;
unsigned int i, stream_num = 1;
int ret, is_reset = 0;
struct rkmodule_vicap_reset_info rst_info;
@@ -5013,10 +5206,10 @@ void rkcif_reset_watchdog_timer_handler(struct timer_list *t)
if (timer->run_cnt <= timer->max_run_cnt) {
mod_timer(&timer->timer, jiffies + timer->cycle);
} else {
spin_lock_irqsave(&timer->timer_lock, lock_flags);
spin_lock_irqsave(&timer->timer_lock, flags);
timer->is_triggered = false;
timer->is_running = false;
spin_unlock_irqrestore(&timer->timer_lock, lock_flags);
spin_unlock_irqrestore(&timer->timer_lock, flags);
v4l2_info(&dev->v4l2_dev, "stop reset detecting!\n");
}
}
@@ -5041,10 +5234,10 @@ void rkcif_reset_watchdog_timer_handler(struct timer_list *t)
return;
end_detect:
spin_lock_irqsave(&timer->timer_lock, lock_flags);
spin_lock_irqsave(&timer->timer_lock, flags);
timer->is_triggered = false;
timer->is_running = false;
spin_unlock_irqrestore(&timer->timer_lock, lock_flags);
spin_unlock_irqrestore(&timer->timer_lock, flags);
v4l2_info(&dev->v4l2_dev,
"stream[%d] is stopped, stop reset detect!\n",
@@ -5056,11 +5249,11 @@ int rkcif_reset_notifier(struct notifier_block *nb,
{
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;
unsigned long flags, val;
if (timer->is_running) {
val = action & CSI2_ERR_COUNT_ALL_MASK;
spin_lock_irqsave(&timer->csi2_err_lock, lock_flags);
spin_lock_irqsave(&timer->csi2_err_lock, flags);
if ((val % timer->csi2_err_ref_cnt) == 0) {
timer->notifer_called_cnt++;
if ((timer->notifer_called_cnt % 2) == 0)
@@ -5070,18 +5263,69 @@ int rkcif_reset_notifier(struct notifier_block *nb,
}
timer->csi2_err_fs_fe_cnt = (action & CSI2_ERR_FSFE_MASK) >> 8;
spin_unlock_irqrestore(&timer->csi2_err_lock, lock_flags);
spin_unlock_irqrestore(&timer->csi2_err_lock, flags);
}
return 0;
}
static void rkcif_modify_line_int(struct rkcif_stream *stream, bool en)
{
struct rkcif_device *cif_dev = stream->cifdev;
if (en) {
if (cif_dev->wait_line_bak != cif_dev->wait_line) {
cif_dev->wait_line_bak = cif_dev->wait_line;
rkcif_write_register(cif_dev, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1,
cif_dev->wait_line << 16 | cif_dev->wait_line);
rkcif_write_register(cif_dev, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3,
cif_dev->wait_line << 16 | cif_dev->wait_line);
}
rkcif_write_register_or(cif_dev, CIF_REG_MIPI_LVDS_INTEN,
CSI_LINE_INTEN(stream->id));
} else {
rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_INTEN,
~(CSI_LINE_INTEN(stream->id)));
}
}
static void rkcif_detect_wake_up_mode_change(struct rkcif_stream *stream)
{
struct rkcif_device *cif_dev = stream->cifdev;
if (cif_dev->wait_line && (!stream->is_line_wake_up)) {
stream->is_line_wake_up = true;
if (stream->frame_phase == CIF_CSI_FRAME0_READY)
stream->line_int_cnt = 1;
else if (stream->frame_phase == CIF_CSI_FRAME1_READY)
stream->line_int_cnt = 0;
} else if ((cif_dev->wait_line == 0) && stream->is_line_wake_up) {
stream->is_line_wake_up = false;
}
if (stream->is_line_wake_up) {
rkcif_modify_line_int(stream, true);
stream->is_line_inten = true;
}
if (cif_dev->hdr.mode == NO_HDR && stream->id == RKCIF_STREAM_MIPI_ID0) {
if (cif_dev->wait_line != cif_dev->wait_line_cache)
cif_dev->wait_line = cif_dev->wait_line_cache;
} else if (cif_dev->hdr.mode == HDR_X2 && stream->id == RKCIF_STREAM_MIPI_ID1) {
if (cif_dev->wait_line != cif_dev->wait_line_cache)
cif_dev->wait_line = cif_dev->wait_line_cache;
} else if (cif_dev->hdr.mode == HDR_X3 && stream->id == RKCIF_STREAM_MIPI_ID2) {
if (cif_dev->wait_line != cif_dev->wait_line_cache)
cif_dev->wait_line = cif_dev->wait_line_cache;
}
}
void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
{
struct rkcif_stream *stream;
struct rkcif_stream *detect_stream = &cif_dev->stream[0];
struct v4l2_mbus_config *mbus;
unsigned int intstat = 0x0, i = 0xff, bak_intstat = 0x0;
unsigned long flags;
int ret = 0;
if (!cif_dev->active_sensor)
@@ -5136,12 +5380,10 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
rkcif_csi2_event_inc_sof();
else if (mbus->type == V4L2_MBUS_CCP2)
rkcif_lvds_event_inc_sof(cif_dev);
if (detect_stream->fs_cnt_in_single_frame >= 1)
v4l2_warn(&cif_dev->v4l2_dev,
"%s:warn: fs has been incread:%u(frm0)\n",
__func__, detect_stream->fs_cnt_in_single_frame);
detect_stream->fs_cnt_in_single_frame++;
spin_lock_irqsave(&detect_stream->fps_lock, flags);
detect_stream->readout.fs_timestamp = ktime_get_ns();
spin_unlock_irqrestore(&detect_stream->fps_lock, flags);
}
if (intstat & CSI_FRAME1_START_ID0) {
@@ -5149,11 +5391,23 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
rkcif_csi2_event_inc_sof();
else if (mbus->type == V4L2_MBUS_CCP2)
rkcif_lvds_event_inc_sof(cif_dev);
if (detect_stream->fs_cnt_in_single_frame >= 1)
v4l2_warn(&cif_dev->v4l2_dev, "%s:warn: fs has been incread:%u(frm1)\n",
__func__, detect_stream->fs_cnt_in_single_frame);
detect_stream->fs_cnt_in_single_frame++;
spin_lock_irqsave(&detect_stream->fps_lock, flags);
detect_stream->readout.fs_timestamp = ktime_get_ns();
spin_unlock_irqrestore(&detect_stream->fps_lock, flags);
}
for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) {
if (intstat & CSI_LINE_INTSTAT(i)) {
stream = &cif_dev->stream[i];
if (stream->is_line_inten) {
stream->line_int_cnt++;
rkcif_line_wake_up(stream, stream->id);
rkcif_modify_line_int(stream, false);
stream->is_line_inten = false;
}
v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev,
"%s: id0 cur line:%d\n", __func__, lastline & 0x3fff);
}
}
/* if do not reach frame dma end, return irq */
@@ -5168,8 +5422,7 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
continue;
stream = &cif_dev->stream[mipi_id];
if (stream->stopping) {
if (stream->stopping && stream->is_can_stop) {
rkcif_stream_stop(stream);
stream->stopping = false;
wake_up(&stream->wq_stopped);
@@ -5202,6 +5455,7 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
rkcif_dynamic_crop(stream);
rkcif_update_stream(cif_dev, stream, mipi_id);
rkcif_detect_wake_up_mode_change(stream);
rkcif_monitor_reset_event(cif_dev);
if (mipi_id == RKCIF_STREAM_MIPI_ID0) {
if ((intstat & (CSI_FRAME1_START_ID0 | CSI_FRAME0_START_ID0)) == 0 &&
@@ -5338,12 +5592,12 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
stream->frame_phase = CIF_CSI_FRAME1_READY;
}
spin_lock(&stream->fps_lock);
spin_lock_irqsave(&stream->fps_lock, flags);
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);
spin_unlock_irqrestore(&stream->fps_lock, flags);
ret = rkcif_assign_new_buffer_oneframe(stream,
RKCIF_YUV_ADDR_STATE_UPDATE);

View File

@@ -91,11 +91,44 @@ static ssize_t rkcif_store_compact_mode(struct device *dev,
return len;
}
static ssize_t rkcif_show_line_int_num(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev);
int ret;
ret = snprintf(buf, PAGE_SIZE, "%d\n",
cif_dev->wait_line_cache);
return ret;
}
static ssize_t rkcif_store_line_int_num(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev);
int val = 0;
int ret = 0;
ret = kstrtoint(buf, 0, &val);
if (!ret && val >= 0 && val <= 0x3fff)
cif_dev->wait_line_cache = val;
else
dev_info(cif_dev->dev, "set line int num failed\n");
return len;
}
static DEVICE_ATTR(compact_test, S_IWUSR | S_IRUSR,
rkcif_show_compact_mode, rkcif_store_compact_mode);
static DEVICE_ATTR(wait_line, S_IWUSR | S_IRUSR,
rkcif_show_line_int_num, rkcif_store_line_int_num);
static struct attribute *dev_attrs[] = {
&dev_attr_compact_test.attr,
&dev_attr_wait_line.attr,
NULL,
};
@@ -1149,6 +1182,19 @@ static const struct of_device_id rkcif_plat_of_match[] = {
{},
};
static void rkcif_parse_dts(struct rkcif_device *cif_dev)
{
int ret = 0;
struct device_node *node = cif_dev->dev->of_node;
ret = of_property_read_u32(node,
OF_CIF_WAIT_LINE,
&cif_dev->wait_line);
if (ret != 0)
cif_dev->wait_line = 0;
dev_info(cif_dev->dev, "rkcif wait line %d\n", cif_dev->wait_line);
}
static int rkcif_plat_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
@@ -1182,6 +1228,8 @@ static int rkcif_plat_probe(struct platform_device *pdev)
rkcif_attach_hw(cif_dev);
rkcif_parse_dts(cif_dev);
ret = rkcif_plat_init(cif_dev, node, data->inf_id);
if (ret) {
rkcif_detach_hw(cif_dev);

View File

@@ -29,6 +29,8 @@
#define CIF_VIDEODEVICE_NAME "stream_cif"
#define OF_CIF_MONITOR_PARA "rockchip,cif-monitor"
#define OF_CIF_WAIT_LINE "wait-line"
#define CIF_MONITOR_PARA_NUM (5)
#define RKCIF_SINGLE_STREAM 1
@@ -283,6 +285,23 @@ struct rkcif_fps_stats {
u64 frm1_timestamp;
};
/* struct rkcif_fps_stats - take notes on timestamp of buf
* @fs_timestamp: timesstamp of frame start
* @fe_timestamp: timesstamp of frame end
* @wk_timestamp: timesstamp of buf send to user in wake up mode
* @readout_time: one frame of readout time
* @early_time: early time of buf send to user
* @total_time: totaltime of readout time in hdr
*/
struct rkcif_readout_stats {
u64 fs_timestamp;
u64 fe_timestamp;
u64 wk_timestamp;
u64 readout_time;
u64 early_time;
u64 total_time;
};
/* struct rkcif_irq_stats - take notes on irq number
* @csi_overflow_cnt: count of csi overflow irq
* @csi_bwidth_lack_cnt: count of csi bandwidth lack irq
@@ -385,10 +404,6 @@ struct rkcif_stream {
struct rkcif_device *cifdev;
struct rkcif_vdev_node vnode;
enum rkcif_state state;
bool stopping;
bool crop_enable;
bool crop_dyn_en;
bool is_compact;
wait_queue_head_t wq_stopped;
unsigned int frame_idx;
int frame_phase;
@@ -409,9 +424,19 @@ struct rkcif_stream {
struct v4l2_rect crop[CROP_SRC_MAX];
struct rkcif_fps_stats fps_stats;
struct rkcif_extend_info extend_line;
struct rkcif_readout_stats readout;
unsigned int fs_cnt_in_single_frame;
u64 line_int_cnt;
bool stopping;
bool crop_enable;
bool crop_dyn_en;
bool is_compact;
bool is_dvp_yuv_addr_init;
bool is_fs_fe_not_paired;
unsigned int fs_cnt_in_single_frame;
bool is_line_wake_up;
bool is_line_inten;
bool is_can_stop;
bool is_buf_active;
};
struct rkcif_lvds_subdev {
@@ -505,16 +530,17 @@ struct rkcif_device {
struct proc_dir_entry *proc_dir;
struct rkcif_irq_stats irq_stats;
spinlock_t hdr_lock; /* lock for hdr buf sync */
bool is_start_hdr;
struct notifier_block reset_notifier; /* reset for mipi csi crc err */
struct rkcif_work_struct reset_work;
bool reset_work_cancel;
struct rkcif_timer reset_watchdog_timer;
unsigned int buf_wake_up_cnt;
bool iommu_en;
struct notifier_block reset_notifier; /* reset for mipi csi crc err */
struct rkcif_work_struct reset_work;
unsigned int dvp_sof_in_oneframe;
unsigned int wait_line;
unsigned int wait_line_bak;
unsigned int wait_line_cache;
bool is_start_hdr;
bool reset_work_cancel;
bool iommu_en;
};
extern struct platform_driver rkcif_plat_drv;

View File

@@ -249,9 +249,10 @@ static void rkcif_show_format(struct rkcif_device *dev, struct seq_file *f)
struct v4l2_rect *rect = &sensor->raw_rect;
struct v4l2_subdev_frame_interval *interval = &sensor->fi;
struct v4l2_subdev_selection *sel = &sensor->selection;
u32 i, flags;
u32 i, mbus_flags;
u64 fps, timestamp0, timestamp1;
unsigned long lock_flags = 0;
unsigned long flags;
u32 time_val = 0;
if (atomic_read(&pipe->stream_cnt) < 1)
return;
@@ -260,24 +261,24 @@ static void rkcif_show_format(struct rkcif_device *dev, struct seq_file *f)
seq_puts(f, "Input Info:\n");
seq_printf(f, "\tsrc subdev:%s\n", sensor->sd->name);
flags = sensor->mbus.flags;
mbus_flags = sensor->mbus.flags;
if (sensor->mbus.type == V4L2_MBUS_PARALLEL ||
sensor->mbus.type == V4L2_MBUS_BT656) {
seq_printf(f, "\tinterface:%s\n",
sensor->mbus.type == V4L2_MBUS_PARALLEL ? "BT601" : "BT656/BT1120");
seq_printf(f, "\thref_pol:%s\n",
flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH ? "high active" : "low active");
mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH ? "high active" : "low active");
seq_printf(f, "\tvsync_pol:%s\n",
flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH ? "high active" : "low active");
mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH ? "high active" : "low active");
} else {
seq_printf(f, "\tinterface:%s\n",
sensor->mbus.type == V4L2_MBUS_CSI2 ? "mipi csi2" :
sensor->mbus.type == V4L2_MBUS_CCP2 ? "lvds" : "unknown");
seq_printf(f, "\tlanes:%d\n", sensor->lanes);
seq_puts(f, "\tvc channel:");
if (flags & V4L2_MBUS_CSI2_CHANNELS) {
if (mbus_flags & V4L2_MBUS_CSI2_CHANNELS) {
for (i = 0; i < 4; i++) {
if ((flags >> (4 + i)) & 0x1)
if ((mbus_flags >> (4 + i)) & 0x1)
seq_printf(f, " %d", i);
}
seq_puts(f, "\n");
@@ -299,14 +300,13 @@ static void rkcif_show_format(struct rkcif_device *dev, struct seq_file *f)
sel->r.left, sel->r.top,
sel->r.width, sel->r.height);
spin_lock_irqsave(&stream->fps_lock, lock_flags);
spin_lock_irqsave(&stream->fps_lock, flags);
timestamp0 = stream->fps_stats.frm0_timestamp;
timestamp1 = stream->fps_stats.frm1_timestamp;
spin_unlock_irqrestore(&stream->fps_lock, lock_flags);
spin_unlock_irqrestore(&stream->fps_lock, flags);
fps = timestamp0 > timestamp1 ?
timestamp0 - timestamp1 : timestamp1 - timestamp0;
fps = div_u64(fps, 1000000);
fps = div_u64(1000, fps);
seq_puts(f, "Output Info:\n");
seq_printf(f, "\tformat:%s/%ux%u(%u,%u)\n",
@@ -315,6 +315,20 @@ static void rkcif_show_format(struct rkcif_device *dev, struct seq_file *f)
dev->channels[0].crop_st_x, dev->channels[0].crop_st_y);
seq_printf(f, "\tcompact:%s\n", stream->is_compact ? "enable" : "disabled");
seq_printf(f, "\tframe amount:%d\n", stream->frame_idx);
time_val = div_u64(stream->readout.early_time, 1000000);
seq_printf(f, "\tearly:%u ms\n", time_val);
if (dev->hdr.mode == NO_HDR) {
time_val = div_u64(stream->readout.readout_time, 1000000);
seq_printf(f, "\treadout:%u ms\n", time_val);
} else {
time_val = div_u64(stream->readout.readout_time, 1000000);
seq_printf(f, "\tsingle readout:%u ms\n", time_val);
time_val = div_u64(stream->readout.total_time, 1000000);
seq_printf(f, "\ttotal readout:%u ms\n", time_val);
}
seq_printf(f, "\trate:%llu ms\n", fps);
fps = div_u64(1000, fps);
seq_printf(f, "\tfps:%llu\n", fps);
seq_puts(f, "\tirq statistics:\n");
seq_printf(f, "\t\t\ttotal:%llu\n",

View File

@@ -63,6 +63,7 @@
*3. optimize dts config of cif's pipeline
*4. register cif itf dev when clear unready subdev
*5. mipi csi host add cru rst
*6. support wake up mode with mipi
*/
#define RKCIF_DRIVER_VERSION RKCIF_API_VERSION