mirror of
https://github.com/torvalds/linux.git
synced 2026-06-08 14:42:37 +02:00
media: rockchip: isp1: selfpath support interlace input
Change-Id: I4a69abac4cc2627e6899e4f49123e8f875524487 Signed-off-by: Cai YiWei <cyw@rock-chips.com>
This commit is contained in:
parent
c955146087
commit
70f89eed1a
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user