media: rockchip: isp1: selfpath support interlace input

Change-Id: I4a69abac4cc2627e6899e4f49123e8f875524487
Signed-off-by: Cai YiWei <cyw@rock-chips.com>
This commit is contained in:
Cai YiWei 2018-12-27 17:16:13 +08:00 committed by Tao Huang
parent c955146087
commit 70f89eed1a
3 changed files with 118 additions and 18 deletions

View File

@ -864,6 +864,25 @@ static u32 calc_burst_len(struct rkisp1_stream *stream)
for (i = 0; i < RKISP1_MAX_STREAM; i++)
if (burst > dev->stream[i].burst)
burst = dev->stream[i].burst;
if (stream->interlaced) {
if (!stream->out_fmt.width % (bus * 16))
stream->burst = CIF_MI_CTRL_BURST_LEN_LUM_16 |
CIF_MI_CTRL_BURST_LEN_CHROM_16;
else if (!stream->out_fmt.width % (bus * 8))
stream->burst = CIF_MI_CTRL_BURST_LEN_LUM_8 |
CIF_MI_CTRL_BURST_LEN_CHROM_8;
else
stream->burst = CIF_MI_CTRL_BURST_LEN_LUM_4 |
CIF_MI_CTRL_BURST_LEN_CHROM_4;
if (stream->out_fmt.width % (bus * 4))
v4l2_warn(&dev->v4l2_dev,
"interlaced: width should be %d aligned\n",
bus * 4);
burst = min(stream->burst, burst);
stream->burst = burst;
}
return burst;
}
@ -923,8 +942,15 @@ static int sp_config_mi(struct rkisp1_stream *stream)
mi_set_cr_size(stream, stream->out_fmt.plane_fmt[2].sizeimage);
sp_set_y_width(base, stream->out_fmt.width);
sp_set_y_height(base, stream->out_fmt.height);
sp_set_y_line_length(base, stream->u.sp.y_stride);
if (stream->interlaced) {
stream->u.sp.vir_offs =
stream->out_fmt.plane_fmt[0].bytesperline;
sp_set_y_height(base, stream->out_fmt.height / 2);
sp_set_y_line_length(base, stream->u.sp.y_stride * 2);
} else {
sp_set_y_height(base, stream->out_fmt.height);
sp_set_y_line_length(base, stream->u.sp.y_stride);
}
mi_frame_end_int_enable(stream);
if (output_isp_fmt->uv_swap)
@ -1126,10 +1152,14 @@ static int mi_frame_end(struct rkisp1_stream *stream)
struct rkisp1_device *isp_dev = stream->ispdev;
struct rkisp1_isp_subdev *isp_sd = &isp_dev->isp_sdev;
struct capture_fmt *isp_fmt = &stream->out_isp_fmt;
bool interlaced = stream->interlaced;
unsigned long lock_flags = 0;
int i = 0;
if (stream->curr_buf) {
if (stream->curr_buf &&
(!interlaced ||
(stream->u.sp.field_rec == RKISP_FIELD_ODD &&
stream->u.sp.field == RKISP_FIELD_EVEN))) {
u64 ns = ktime_get_ns();
/* Dequeue a filled buffer */
@ -1145,24 +1175,47 @@ static int mi_frame_end(struct rkisp1_stream *stream)
stream->curr_buf->vb.timestamp = ns_to_timeval(ns);
vb2_buffer_done(&stream->curr_buf->vb.vb2_buf,
VB2_BUF_STATE_DONE);
stream->curr_buf = NULL;
}
/* Next frame is writing to it */
stream->curr_buf = stream->next_buf;
stream->next_buf = NULL;
if (!interlaced ||
(stream->curr_buf == stream->next_buf &&
stream->u.sp.field == RKISP_FIELD_ODD)) {
/* Next frame is writing to it
* Interlaced: odd field next buffer address
*/
stream->curr_buf = stream->next_buf;
stream->next_buf = NULL;
/* Set up an empty buffer for the next-next frame */
spin_lock_irqsave(&stream->vbq_lock, lock_flags);
if (!list_empty(&stream->buf_queue)) {
stream->next_buf = list_first_entry(&stream->buf_queue,
struct rkisp1_buffer, queue);
list_del(&stream->next_buf->queue);
/* Set up an empty buffer for the next-next frame */
spin_lock_irqsave(&stream->vbq_lock, lock_flags);
if (!list_empty(&stream->buf_queue)) {
stream->next_buf =
list_first_entry(&stream->buf_queue,
struct rkisp1_buffer,
queue);
list_del(&stream->next_buf->queue);
}
spin_unlock_irqrestore(&stream->vbq_lock, lock_flags);
} else if (stream->u.sp.field_rec == RKISP_FIELD_ODD &&
stream->u.sp.field == RKISP_FIELD_EVEN) {
/* Interlaced: event field next buffer address */
if (stream->next_buf) {
stream->next_buf->buff_addr[RKISP1_PLANE_Y] +=
stream->u.sp.vir_offs;
stream->next_buf->buff_addr[RKISP1_PLANE_CB] +=
stream->u.sp.vir_offs;
stream->next_buf->buff_addr[RKISP1_PLANE_CR] +=
stream->u.sp.vir_offs;
}
stream->curr_buf = stream->next_buf;
}
spin_unlock_irqrestore(&stream->vbq_lock, lock_flags);
stream->ops->update_mi(stream);
if (interlaced)
stream->u.sp.field_rec = stream->u.sp.field;
return 0;
}
@ -1195,6 +1248,7 @@ static void rkisp1_stream_stop(struct rkisp1_stream *stream)
stream->burst =
CIF_MI_CTRL_BURST_LEN_LUM_16 |
CIF_MI_CTRL_BURST_LEN_CHROM_16;
stream->interlaced = false;
}
/*
@ -1344,7 +1398,8 @@ static void rkisp1_buf_queue(struct vb2_buffer *vb)
/* XXX: replace dummy to speed up */
if (stream->streaming &&
stream->next_buf == NULL &&
!stream->next_buf &&
!stream->interlaced &&
stream->id != RKISP1_STREAM_RAW &&
atomic_read(&stream->ispdev->isp_sdev.frm_sync_seq) == 0) {
stream->next_buf = ispbuf;
@ -1418,6 +1473,8 @@ static void rkisp1_stop_streaming(struct vb2_queue *queue)
spin_lock_irqsave(&stream->vbq_lock, lock_flags);
if (stream->curr_buf) {
list_add_tail(&stream->curr_buf->queue, &stream->buf_queue);
if (stream->curr_buf == stream->next_buf)
stream->next_buf = NULL;
stream->curr_buf = NULL;
}
if (stream->next_buf) {
@ -1495,6 +1552,19 @@ rkisp1_start_streaming(struct vb2_queue *queue, unsigned int count)
}
}
if (dev->active_sensor &&
dev->active_sensor->fmt.format.field ==
V4L2_FIELD_INTERLACED) {
if (stream->id != RKISP1_STREAM_SP) {
v4l2_err(v4l2_dev,
"only selfpath support interlaced\n");
return -EINVAL;
}
stream->interlaced = true;
stream->u.sp.field = RKISP_FIELD_INVAL;
stream->u.sp.field_rec = RKISP_FIELD_INVAL;
}
ret = rkisp1_create_dummy_buf(stream);
if (ret < 0)
return ret;
@ -1764,6 +1834,7 @@ void rkisp1_stream_init(struct rkisp1_device *dev, u32 id)
}
stream->streaming = false;
stream->interlaced = false;
rkisp1_set_stream_def_fmt(dev, id,
RKISP1_DEFAULT_WIDTH,
RKISP1_DEFAULT_HEIGHT,

View File

@ -70,9 +70,18 @@ enum rkisp1_sp_inp {
RKISP1_SP_INP_MAX
};
enum rkisp1_field {
RKISP_FIELD_ODD,
RKISP_FIELD_EVEN,
RKISP_FIELD_INVAL,
};
struct rkisp1_stream_sp {
int y_stride;
int vir_offs;
enum rkisp1_sp_inp input_sel;
enum rkisp1_field field;
enum rkisp1_field field_rec;
};
struct rkisp1_stream_mp {
@ -167,6 +176,7 @@ struct streams_ops {
*/
struct rkisp1_stream {
unsigned id:2;
unsigned interlaced:1;
struct rkisp1_device *ispdev;
struct rkisp1_vdev_node vnode;
struct capture_fmt out_isp_fmt;

View File

@ -172,7 +172,10 @@ static void rkisp1_config_ism(struct rkisp1_device *dev)
writel(out_crop->left, base + CIF_ISP_IS_H_OFFS);
writel(out_crop->top, base + CIF_ISP_IS_V_OFFS);
writel(out_crop->width, base + CIF_ISP_IS_H_SIZE);
writel(out_crop->height, base + CIF_ISP_IS_V_SIZE);
if (dev->stream[RKISP1_STREAM_SP].interlaced)
writel(out_crop->height / 2, base + CIF_ISP_IS_V_SIZE);
else
writel(out_crop->height, base + CIF_ISP_IS_V_SIZE);
/* IS(Image Stabilization) is always on, working as output crop */
writel(1, base + CIF_ISP_IS_CTRL);
@ -271,13 +274,19 @@ static int rkisp1_config_isp(struct rkisp1_device *dev)
writel(0, base + CIF_ISP_ACQ_H_OFFS);
writel(0, base + CIF_ISP_ACQ_V_OFFS);
writel(acq_mult * in_frm->width, base + CIF_ISP_ACQ_H_SIZE);
writel(in_frm->height, base + CIF_ISP_ACQ_V_SIZE);
/* ISP Out Area */
writel(in_crop->left, base + CIF_ISP_OUT_H_OFFS);
writel(in_crop->top, base + CIF_ISP_OUT_V_OFFS);
writel(in_crop->width, base + CIF_ISP_OUT_H_SIZE);
writel(in_crop->height, base + CIF_ISP_OUT_V_SIZE);
if (dev->stream[RKISP1_STREAM_SP].interlaced) {
writel(in_frm->height / 2, base + CIF_ISP_ACQ_V_SIZE);
writel(in_crop->height / 2, base + CIF_ISP_OUT_V_SIZE);
} else {
writel(in_frm->height, base + CIF_ISP_ACQ_V_SIZE);
writel(in_crop->height, base + CIF_ISP_OUT_V_SIZE);
}
/* interrupt mask */
irq_mask |= CIF_ISP_FRAME | CIF_ISP_V_START | CIF_ISP_PIC_SIZE_ERROR |
@ -1420,6 +1429,16 @@ void rkisp1_isp_isr(unsigned int isp_mis, struct rkisp1_device *dev)
/* start edge of v_sync */
if (isp_mis & CIF_ISP_V_START) {
if (dev->stream[RKISP1_STREAM_SP].interlaced) {
/* 0 = ODD 1 = EVEN */
if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2)
dev->stream[RKISP1_STREAM_SP].u.sp.field =
(readl(base + CIF_MIPI_FRAME) >> 16) % 2;
else
dev->stream[RKISP1_STREAM_SP].u.sp.field =
(readl(base + CIF_ISP_FLAGS_SHD) >> 2) & BIT(0);
}
if (dev->vs_irq < 0)
riksp1_isp_queue_event_sof(&dev->isp_sdev);