1329 lines
35 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */
#include <linux/delay.h>
#include <linux/pm_runtime.h>
#include <media/v4l2-common.h>
#include <media/v4l2-event.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-subdev.h>
#include <media/videobuf2-dma-contig.h>
#include <media/videobuf2-dma-sg.h>
#include "dev.h"
#include "regs.h"
#define CIF_ISP_REQ_BUFS_MIN 0
static const struct capture_fmt dmarx_fmts[] = {
/* bayer raw */
{
.fourcc = V4L2_PIX_FMT_SRGGB8,
.mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
.fmt_type = FMT_BAYER,
.bpp = { 8 },
.mplanes = 1,
.write_format = CIF_MI_DMA_CTRL_READ_FMT_PACKED,
.output_format = CIF_MI_DMA_CTRL_RGB_BAYER_8BIT,
}, {
.fourcc = V4L2_PIX_FMT_SGRBG8,
.mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
.fmt_type = FMT_BAYER,
.bpp = { 8 },
.mplanes = 1,
.write_format = CIF_MI_DMA_CTRL_READ_FMT_PACKED,
.output_format = CIF_MI_DMA_CTRL_RGB_BAYER_8BIT,
}, {
.fourcc = V4L2_PIX_FMT_SGBRG8,
.mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
.fmt_type = FMT_BAYER,
.bpp = { 8 },
.mplanes = 1,
.write_format = CIF_MI_DMA_CTRL_READ_FMT_PACKED,
.output_format = CIF_MI_DMA_CTRL_RGB_BAYER_8BIT,
}, {
.fourcc = V4L2_PIX_FMT_SBGGR8,
.mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
.fmt_type = FMT_BAYER,
.bpp = { 8 },
.mplanes = 1,
.write_format = CIF_MI_DMA_CTRL_READ_FMT_PACKED,
.output_format = CIF_MI_DMA_CTRL_RGB_BAYER_8BIT,
}, { /* 12bit used, 4 lower bits of LSB unused */
.fourcc = V4L2_PIX_FMT_SBGGR16,
.mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
.fmt_type = FMT_BAYER,
.bpp = { 16 },
.mplanes = 1,
.write_format = CIF_MI_DMA_CTRL_READ_FMT_PACKED,
.output_format = CIF_MI_DMA_CTRL_RGB_BAYER_16BIT,
}, {
.fourcc = V4L2_PIX_FMT_YUYV,
.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.fmt_type = FMT_YUV,
.bpp = { 16 },
.cplanes = 1,
.mplanes = 1,
.uv_swap = 0,
.write_format = CIF_MI_DMA_CTRL_READ_FMT_PACKED,
.output_format = CIF_MI_DMA_CTRL_FMT_YUV422,
}, {
.fourcc = V4L2_PIX_FMT_YVYU,
.mbus_code = MEDIA_BUS_FMT_YVYU8_2X8,
.fmt_type = FMT_YUV,
.bpp = { 16 },
.cplanes = 1,
.mplanes = 1,
.uv_swap = 0,
.write_format = CIF_MI_DMA_CTRL_READ_FMT_PACKED,
.output_format = CIF_MI_DMA_CTRL_FMT_YUV422,
}, {
.fourcc = V4L2_PIX_FMT_UYVY,
.mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
.fmt_type = FMT_YUV,
.bpp = { 16 },
.cplanes = 1,
.mplanes = 1,
.uv_swap = 0,
.write_format = CIF_MI_DMA_CTRL_READ_FMT_PACKED,
.output_format = CIF_MI_DMA_CTRL_FMT_YUV422,
}, {
.fourcc = V4L2_PIX_FMT_VYUY,
.mbus_code = MEDIA_BUS_FMT_VYUY8_2X8,
.fmt_type = FMT_YUV,
.bpp = { 16 },
.cplanes = 1,
.mplanes = 1,
.uv_swap = 0,
.write_format = CIF_MI_DMA_CTRL_READ_FMT_PACKED,
.output_format = CIF_MI_DMA_CTRL_FMT_YUV422,
}
};
static const struct capture_fmt rawrd_fmts[] = {
{
.fourcc = V4L2_PIX_FMT_SRGGB8,
.fmt_type = FMT_BAYER,
.bpp = { 8 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_SGRBG8,
.fmt_type = FMT_BAYER,
.bpp = { 8 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_SGBRG8,
.fmt_type = FMT_BAYER,
.bpp = { 8 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_SBGGR8,
.fmt_type = FMT_BAYER,
.bpp = { 8 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_GREY,
.fmt_type = FMT_BAYER,
.bpp = { 8 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_SRGGB10,
.fmt_type = FMT_BAYER,
.bpp = { 10 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_SGRBG10,
.fmt_type = FMT_BAYER,
.bpp = { 10 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_SGBRG10,
.fmt_type = FMT_BAYER,
.bpp = { 10 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.fmt_type = FMT_BAYER,
.bpp = { 10 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_Y10,
.fmt_type = FMT_BAYER,
.bpp = { 10 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_SRGGB12,
.fmt_type = FMT_BAYER,
.bpp = { 12 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_SGRBG12,
.fmt_type = FMT_BAYER,
.bpp = { 12 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_SGBRG12,
.fmt_type = FMT_BAYER,
.bpp = { 12 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_SBGGR12,
.fmt_type = FMT_BAYER,
.bpp = { 12 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_Y12,
.fmt_type = FMT_BAYER,
.bpp = { 12 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_YUYV,
.fmt_type = FMT_YUV,
.bpp = { 16 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_YVYU,
.fmt_type = FMT_YUV,
.bpp = { 16 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_UYVY,
.fmt_type = FMT_YUV,
.bpp = { 16 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_VYUY,
.fmt_type = FMT_YUV,
.bpp = { 16 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_SRGGB16,
.fmt_type = FMT_BAYER,
.bpp = { 16 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_SGRBG16,
.fmt_type = FMT_BAYER,
.bpp = { 16 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_SGBRG16,
.fmt_type = FMT_BAYER,
.bpp = { 16 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_SBGGR16,
.fmt_type = FMT_BAYER,
.bpp = { 16 },
.mplanes = 1,
}, {
.fourcc = V4L2_PIX_FMT_Y16,
.fmt_type = FMT_BAYER,
.bpp = { 16 },
.mplanes = 1,
}
};
static struct stream_config rkisp_dmarx_stream_config = {
.fmts = dmarx_fmts,
.fmt_size = ARRAY_SIZE(dmarx_fmts),
.mi = {
.y_size_init = CIF_MI_DMA_Y_PIC_SIZE,
.y_base_ad_init = CIF_MI_DMA_Y_PIC_START_AD,
.cb_base_ad_init = CIF_MI_DMA_CB_PIC_START_AD,
.cr_base_ad_init = CIF_MI_DMA_CR_PIC_START_AD,
},
};
static struct stream_config rkisp2_dmarx0_stream_config = {
.fmts = rawrd_fmts,
.fmt_size = ARRAY_SIZE(rawrd_fmts),
.frame_end_id = RAW0_RD_FRAME,
.mi = {
.y_base_ad_init = MI_RAW0_RD_BASE,
.y_base_ad_shd = MI_RAW0_RD_BASE_SHD,
.length = MI_RAW0_RD_LENGTH,
},
};
static struct stream_config rkisp2_dmarx1_stream_config = {
.fmts = rawrd_fmts,
.fmt_size = ARRAY_SIZE(rawrd_fmts),
.frame_end_id = RAW1_RD_FRAME,
.mi = {
.y_base_ad_init = MI_RAW1_RD_BASE,
.y_base_ad_shd = MI_RAW1_RD_BASE_SHD,
.length = MI_RAW1_RD_LENGTH,
},
};
static struct stream_config rkisp2_dmarx2_stream_config = {
.fmts = rawrd_fmts,
.fmt_size = ARRAY_SIZE(rawrd_fmts),
.frame_end_id = RAW2_RD_FRAME,
.mi = {
.y_base_ad_init = MI_RAW2_RD_BASE,
.y_base_ad_shd = MI_RAW2_RD_BASE_SHD,
.length = MI_RAW2_RD_LENGTH,
},
};
static const
struct capture_fmt *find_fmt(struct rkisp_stream *stream,
const u32 pixelfmt)
{
const struct capture_fmt *fmt;
int i;
for (i = 0; i < stream->config->fmt_size; i++) {
fmt = &stream->config->fmts[i];
if (fmt->fourcc == pixelfmt)
return fmt;
}
return NULL;
}
static int dmarx_config_mi(struct rkisp_stream *stream)
{
struct rkisp_device *dev = stream->ispdev;
void __iomem *base = dev->base_addr;
struct capture_fmt *dmarx_in_fmt = &stream->out_isp_fmt;
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
"%s %dx%d y_stride:%d\n", __func__,
stream->out_fmt.width,
stream->out_fmt.height,
stream->u.dmarx.y_stride);
mi_set_y_size(stream, stream->out_fmt.width *
stream->out_fmt.height);
dmarx_set_y_width(base, stream->out_fmt.width);
dmarx_set_y_line_length(base, stream->u.dmarx.y_stride);
mi_dmarx_ready_enable(stream);
if (dmarx_in_fmt->uv_swap)
dmarx_set_uv_swap(base);
dmarx_ctrl(base,
dmarx_in_fmt->write_format |
dmarx_in_fmt->output_format |
CIF_MI_DMA_CTRL_BURST_LEN_LUM_16 |
CIF_MI_DMA_CTRL_BURST_LEN_CHROM_16);
return 0;
}
static void update_dmarx(struct rkisp_stream *stream)
{
void __iomem *base = stream->ispdev->base_addr;
if (stream->curr_buf) {
mi_set_y_addr(stream,
stream->curr_buf->buff_addr[RKISP_PLANE_Y]);
mi_set_cb_addr(stream,
stream->curr_buf->buff_addr[RKISP_PLANE_CB]);
mi_set_cr_addr(stream,
stream->curr_buf->buff_addr[RKISP_PLANE_CR]);
mi_dmarx_start(base);
stream->frame_end = false;
}
}
static void dmarx_stop_mi(struct rkisp_stream *stream)
{
mi_dmarx_ready_disable(stream);
}
static struct streams_ops rkisp_dmarx_streams_ops = {
.config_mi = dmarx_config_mi,
.stop_mi = dmarx_stop_mi,
.update_mi = update_dmarx,
};
static int rawrd_config_mi(struct rkisp_stream *stream)
{
struct rkisp_device *dev = stream->ispdev;
u32 val;
val = rkisp_read(dev, CSI2RX_DATA_IDS_1, true);
val &= ~SW_CSI_ID0(0xff);
switch (stream->out_isp_fmt.fourcc) {
case V4L2_PIX_FMT_SRGGB8:
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SGRBG8:
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_GREY:
val |= CIF_CSI2_DT_RAW8;
break;
case V4L2_PIX_FMT_SRGGB10:
case V4L2_PIX_FMT_SBGGR10:
case V4L2_PIX_FMT_SGRBG10:
case V4L2_PIX_FMT_SGBRG10:
case V4L2_PIX_FMT_Y10:
val |= CIF_CSI2_DT_RAW10;
break;
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YVYU:
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_VYUY:
val |= CIF_CSI2_DT_YUV422_8b;
break;
case V4L2_PIX_FMT_SRGGB16:
case V4L2_PIX_FMT_SBGGR16:
case V4L2_PIX_FMT_SGRBG16:
case V4L2_PIX_FMT_SGBRG16:
case V4L2_PIX_FMT_Y16:
val |= CIF_CSI2_DT_RAW16;
break;
default:
val |= CIF_CSI2_DT_RAW12;
}
rkisp_unite_write(dev, CSI2RX_RAW_RD_CTRL,
stream->memory << 2, false);
rkisp_unite_write(dev, CSI2RX_DATA_IDS_1, val, false);
rkisp_rawrd_set_pic_size(dev, stream->out_fmt.width,
stream->out_fmt.height);
mi_raw_length(stream);
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
"%s id:%d 0x%x %dx%d\n", __func__,
stream->id, val,
stream->out_fmt.width,
stream->out_fmt.height);
return 0;
}
static void update_rawrd(struct rkisp_stream *stream)
{
struct rkisp_device *dev = stream->ispdev;
void __iomem *base = dev->base_addr;
struct capture_fmt *fmt = &stream->out_isp_fmt;
u32 offs, offs_h = stream->out_fmt.width / 2 - RKMOUDLE_UNITE_EXTEND_PIXEL;
u32 val = 0;
if (stream->curr_buf) {
if (dev->vicap_in.merge_num > 1) {
val = stream->out_fmt.plane_fmt[0].bytesperline;
val /= dev->vicap_in.merge_num;
val *= dev->vicap_in.index;
}
val += stream->curr_buf->buff_addr[RKISP_PLANE_Y];
rkisp_write(dev, stream->config->mi.y_base_ad_init, val, false);
if (stream->memory)
offs_h *= DIV_ROUND_UP(fmt->bpp[0], 8);
else
offs_h = offs_h * fmt->bpp[0] / 8;
if (dev->unite_div > ISP_UNITE_DIV1)
rkisp_idx_write(dev, stream->config->mi.y_base_ad_init,
val + offs_h, ISP_UNITE_RIGHT, false);
if (dev->unite_div == ISP_UNITE_DIV4) {
offs = stream->out_fmt.plane_fmt[0].bytesperline *
(stream->out_fmt.height / 2 - RKMOUDLE_UNITE_EXTEND_PIXEL);
rkisp_idx_write(dev, stream->config->mi.y_base_ad_init,
val + offs, ISP_UNITE_LEFT_B, false);
offs += offs_h;
rkisp_idx_write(dev, stream->config->mi.y_base_ad_init,
val + offs, ISP_UNITE_RIGHT_B, false);
}
stream->frame_end = false;
if (stream->id == RKISP_STREAM_RAWRD2 && stream->out_isp_fmt.fmt_type == FMT_YUV) {
struct vb2_v4l2_buffer *vbuf = &stream->curr_buf->vb;
struct isp2x_csi_trigger trigger = {
.frame_timestamp = vbuf->vb2_buf.timestamp,
.sof_timestamp = vbuf->vb2_buf.timestamp,
.frame_id = vbuf->sequence,
.mode = 0,
.times = 0,
};
if (!vbuf->sequence)
trigger.frame_id = atomic_inc_return(&dev->isp_sdev.frm_sync_seq) - 1;
rkisp_rdbk_trigger_event(dev, T_CMD_QUEUE, &trigger);
}
} else if (dev->dmarx_dev.trigger == T_AUTO) {
/* internal raw wr/rd buf rotate */
struct rkisp_dummy_buffer *buf;
u32 id, rawwr_addr, val;
switch (stream->id) {
case RKISP_STREAM_RAWRD2:
id = dev->hdr.index[HDR_DMA2];
rawwr_addr = MI_RAW2_WR_BASE_SHD;
break;
case RKISP_STREAM_RAWRD1:
id = dev->hdr.index[HDR_DMA1];
rawwr_addr = MI_RAW1_WR_BASE_SHD;
break;
case RKISP_STREAM_RAWRD0:
default:
id = dev->hdr.index[HDR_DMA0];
rawwr_addr = MI_RAW0_WR_BASE_SHD;
}
if (dev->hdr.rx_cur_buf[id]) {
hdr_qbuf(&dev->hdr.q_tx[id], dev->hdr.rx_cur_buf[id]);
dev->hdr.rx_cur_buf[id] = NULL;
}
buf = hdr_dqbuf(&dev->hdr.q_rx[id]);
if (buf) {
val = buf->dma_addr;
dev->hdr.rx_cur_buf[id] = buf;
} else {
val = readl(base + rawwr_addr);
}
mi_set_y_addr(stream, val);
}
}
static struct streams_ops rkisp2_dmarx_streams_ops = {
.config_mi = rawrd_config_mi,
.update_mi = update_rawrd,
};
static int dmarx_frame_end(struct rkisp_stream *stream)
{
struct rkisp_buffer *buf = NULL;
unsigned long lock_flags = 0;
u32 val, reg;
int on = 1;
spin_lock_irqsave(&stream->vbq_lock, lock_flags);
if (stream->curr_buf) {
buf = stream->curr_buf;
stream->curr_buf = NULL;
}
if (!list_empty(&stream->buf_queue)) {
stream->curr_buf =
list_first_entry(&stream->buf_queue,
struct rkisp_buffer,
queue);
list_del(&stream->curr_buf->queue);
}
if (stream->curr_buf)
stream->ops->update_mi(stream);
spin_unlock_irqrestore(&stream->vbq_lock, lock_flags);
if (buf) {
if (buf->other) {
struct rkisp_device *dev = stream->ispdev;
struct v4l2_subdev *sd = dev->active_sensor->sd;
struct rkisp_rx_buf *rx_buf = buf->other;
if (rx_buf->is_switch && stream->id == RKISP_STREAM_RAWRD2) {
switch (dev->rd_mode) {
case HDR_RDBK_FRAME3:
dev->rd_mode = HDR_LINEX3_DDR;
break;
case HDR_RDBK_FRAME2:
dev->rd_mode = HDR_LINEX2_DDR;
break;
default:
dev->rd_mode = HDR_NORMAL;
}
dev->hdr.op_mode = dev->rd_mode;
val = SW_IBUF_OP_MODE(dev->hdr.op_mode);
rkisp_unite_write(dev, CSI2RX_CTRL0, val, false);
val = ISP21_MIPI_DROP_FRM;
rkisp_unite_set_bits(dev, CSI2RX_MASK_STAT, 0, val, false);
rkisp_unite_clear_bits(dev, CIF_ISP_IMSC, CIF_ISP_FRAME_IN, false);
if (dev->isp_ver == ISP_V33) {
val = ISP33_PP_ENC_PIPE_EN;
rkisp_unite_clear_bits(dev, CTRL_SWS_CFG, val, false);
if (dev->hdr_wrap_line) {
val = stream->out_fmt.plane_fmt[0].bytesperline * dev->hdr_wrap_line;
rkisp_unite_write(dev, ISP32_MI_RAW0_RD_SIZE, val, false);
}
if (dev->unite_div == ISP_UNITE_DIV2) {
mi_raw_length(stream);
reg = stream->config->mi.y_base_ad_init;
rkisp_unite_write(dev, reg, rx_buf->dma, false);
dev->unite_index = ISP_UNITE_LEFT;
dev->params_vdev.rdbk_times = 2;
}
}
dev_info(dev->dev,
"switch online seq:%d mode:0x%x\n",
rx_buf->sequence, dev->rd_mode);
if (dev->hw_dev->is_single)
v4l2_subdev_call(sd, core, ioctl, RKISP_VICAP_CMD_HW_LINK, &on);
}
rx_buf->runtime_us = dev->isp_sdev.dbg.interval / 1000;
v4l2_subdev_call(sd, video, s_rx_buffer, rx_buf, NULL);
} else {
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
}
}
return 0;
}
/***************************** vb2 operations*******************************/
static void dmarx_stop(struct rkisp_stream *stream)
{
struct rkisp_device *dev = stream->ispdev;
struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
int ret = 0;
stream->stopping = true;
if ((dev->isp_state & ISP_START) && !stream->frame_end &&
!dev->hw_dev->is_shutdown) {
ret = wait_event_timeout(stream->done,
!stream->streaming,
msecs_to_jiffies(300));
if (!ret)
v4l2_warn(v4l2_dev,
"dmarx:%d waiting on event return error %d\n",
stream->id, ret);
}
if (stream->ops->stop_mi)
stream->ops->stop_mi(stream);
stream->stopping = false;
stream->streaming = false;
stream->frame_end = false;
}
static int dmarx_start(struct rkisp_stream *stream)
{
int ret;
ret = stream->ops->config_mi(stream);
if (ret)
return ret;
stream->curr_buf = NULL;
stream->streaming = true;
dmarx_frame_end(stream);
return 0;
}
static int rkisp_queue_setup(struct vb2_queue *queue,
unsigned int *num_buffers,
unsigned int *num_planes,
unsigned int sizes[],
struct device *alloc_ctxs[])
{
struct rkisp_stream *stream = queue->drv_priv;
struct rkisp_device *dev = stream->ispdev;
const struct v4l2_pix_format_mplane *pixm = NULL;
const struct capture_fmt *isp_fmt = NULL;
u32 i;
pixm = &stream->out_fmt;
isp_fmt = &stream->out_isp_fmt;
*num_planes = isp_fmt->mplanes;
for (i = 0; i < isp_fmt->mplanes; i++) {
const struct v4l2_plane_pix_format *plane_fmt;
plane_fmt = &pixm->plane_fmt[i];
sizes[i] = plane_fmt->sizeimage;
}
rkisp_chk_tb_over(dev);
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev, "%s %s count %d, size %d\n",
stream->vnode.vdev.name, v4l2_type_names[queue->type], *num_buffers, sizes[0]);
return 0;
}
/*
* The vb2_buffer are stored in rkisp_buffer, in order to unify
* mplane buffer and none-mplane buffer.
*/
static void rkisp_buf_queue(struct vb2_buffer *vb)
{
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct rkisp_buffer *ispbuf = to_rkisp_buffer(vbuf);
struct vb2_queue *queue = vb->vb2_queue;
struct rkisp_stream *stream = queue->drv_priv;
unsigned long lock_flags = 0;
struct v4l2_pix_format_mplane *pixm = &stream->out_fmt;
struct capture_fmt *isp_fmt = &stream->out_isp_fmt;
struct sg_table *sgt;
int i;
ispbuf->other = NULL;
memset(ispbuf->buff_addr, 0, sizeof(ispbuf->buff_addr));
for (i = 0; i < isp_fmt->mplanes; i++) {
void *vaddr = vb2_plane_vaddr(vb, i);
if (vaddr && i == 0 &&
stream->ispdev->isp_ver == ISP_V20 &&
stream->ispdev->rd_mode == HDR_RDBK_FRAME1 &&
RKMODULE_EXTEND_LINE >= 8 &&
isp_fmt->fmt_type == FMT_BAYER &&
stream->id == RKISP_STREAM_RAWRD2) {
u32 line = pixm->plane_fmt[0].bytesperline;
u32 val = RKMODULE_EXTEND_LINE;
vaddr += line * (pixm->height - 2);
while (val) {
memcpy(vaddr + line * val, vaddr, line * 2);
val -= 2;
}
if (vb->vb2_queue->mem_ops->prepare)
vb->vb2_queue->mem_ops->prepare(vb->planes[0].mem_priv);
}
if (stream->ispdev->hw_dev->is_dma_sg_ops) {
sgt = vb2_dma_sg_plane_desc(vb, i);
ispbuf->buff_addr[i] = sg_dma_address(sgt->sgl);
} else {
ispbuf->buff_addr[i] = vb2_dma_contig_plane_dma_addr(vb, i);
}
}
/*
* NOTE: plane_fmt[0].sizeimage is total size of all planes for single
* memory plane formats, so calculate the size explicitly.
*/
if (isp_fmt->mplanes == 1) {
for (i = 0; i < isp_fmt->cplanes - 1; i++) {
ispbuf->buff_addr[i + 1] = (i == 0) ?
ispbuf->buff_addr[i] +
pixm->plane_fmt[i].bytesperline *
pixm->height :
ispbuf->buff_addr[i] +
pixm->plane_fmt[i].sizeimage;
}
}
v4l2_dbg(2, rkisp_debug, &stream->ispdev->v4l2_dev,
"rx:%d queue buf:0x%x\n",
stream->id, ispbuf->buff_addr[0]);
spin_lock_irqsave(&stream->vbq_lock, lock_flags);
if (stream->streaming &&
list_empty(&stream->buf_queue) &&
!stream->curr_buf) {
stream->curr_buf = ispbuf;
stream->ops->update_mi(stream);
} else {
list_add_tail(&ispbuf->queue, &stream->buf_queue);
}
spin_unlock_irqrestore(&stream->vbq_lock, lock_flags);
}
static void destroy_buf_queue(struct rkisp_stream *stream,
enum vb2_buffer_state state)
{
struct rkisp_buffer *buf;
unsigned long lock_flags = 0;
spin_lock_irqsave(&stream->vbq_lock, lock_flags);
if (stream->curr_buf && !stream->curr_buf->other)
list_add_tail(&stream->curr_buf->queue, &stream->buf_queue);
stream->curr_buf = NULL;
while (!list_empty(&stream->buf_queue)) {
buf = list_first_entry(&stream->buf_queue,
struct rkisp_buffer, queue);
list_del(&buf->queue);
if (!buf->other)
vb2_buffer_done(&buf->vb.vb2_buf, state);
}
spin_unlock_irqrestore(&stream->vbq_lock, lock_flags);
}
static void dmarx_stop_streaming(struct vb2_queue *queue)
{
struct rkisp_stream *stream = queue->drv_priv;
struct v4l2_device *v4l2_dev = &stream->ispdev->v4l2_dev;
v4l2_dbg(1, rkisp_debug, v4l2_dev, "%s %s id:%d\n",
__func__, stream->vnode.vdev.name, stream->id);
if (!stream->streaming)
return;
dmarx_stop(stream);
destroy_buf_queue(stream, VB2_BUF_STATE_ERROR);
if (stream->id == RKISP_STREAM_RAWRD2 &&
stream->ispdev->isp_ver >= ISP_V20)
kfifo_reset(&stream->ispdev->rdbk_kfifo);
}
static int dmarx_start_streaming(struct vb2_queue *queue,
unsigned int count)
{
struct rkisp_stream *stream = queue->drv_priv;
struct rkisp_device *dev = stream->ispdev;
struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
int ret = -1;
v4l2_dbg(1, rkisp_debug, v4l2_dev, "%s %s id:%d\n",
__func__, stream->vnode.vdev.name, stream->id);
if (WARN_ON(stream->streaming))
return -EBUSY;
if (!stream->linked) {
v4l2_err(v4l2_dev, "check %s link\n", stream->vnode.vdev.name);
goto free_buf_queue;
}
ret = dmarx_start(stream);
if (ret < 0) {
v4l2_err(v4l2_dev, "start %s failed\n", stream->vnode.vdev.name);
goto free_buf_queue;
}
return 0;
free_buf_queue:
destroy_buf_queue(stream, VB2_BUF_STATE_QUEUED);
return ret;
}
static struct vb2_ops dmarx_vb2_ops = {
.queue_setup = rkisp_queue_setup,
.buf_queue = rkisp_buf_queue,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
.stop_streaming = dmarx_stop_streaming,
.start_streaming = dmarx_start_streaming,
};
static int rkisp_init_vb2_queue(struct vb2_queue *q,
struct rkisp_stream *stream,
enum v4l2_buf_type buf_type)
{
q->type = buf_type;
q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_USERPTR;
q->drv_priv = stream;
q->ops = &dmarx_vb2_ops;
q->mem_ops = stream->ispdev->hw_dev->mem_ops;
q->buf_struct_size = sizeof(struct rkisp_buffer);
q->min_buffers_needed = CIF_ISP_REQ_BUFS_MIN;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
q->lock = &stream->apilock;
q->dev = stream->ispdev->hw_dev->dev;
q->allow_cache_hints = 1;
q->bidirectional = 1;
q->gfp_flags = GFP_DMA32;
if (stream->ispdev->hw_dev->is_dma_contig)
q->dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS;
return vb2_queue_init(q);
}
static int rkisp_set_fmt(struct rkisp_stream *stream,
struct v4l2_pix_format_mplane *pixm,
bool try)
{
const struct capture_fmt *fmt;
unsigned int imagsize = 0;
unsigned int planes;
u32 xsubs = 1, ysubs = 1;
unsigned int i;
fmt = find_fmt(stream, pixm->pixelformat);
if (!fmt) {
v4l2_err(&stream->ispdev->v4l2_dev,
"nonsupport pixelformat:%c%c%c%c\n",
pixm->pixelformat,
pixm->pixelformat >> 8,
pixm->pixelformat >> 16,
pixm->pixelformat >> 24);
return -EINVAL;
}
pixm->num_planes = fmt->mplanes;
pixm->field = V4L2_FIELD_NONE;
if (!pixm->quantization)
pixm->quantization = V4L2_QUANTIZATION_FULL_RANGE;
/* calculate size */
rkisp_fcc_xysubs(fmt->fourcc, &xsubs, &ysubs);
planes = fmt->cplanes ? fmt->cplanes : fmt->mplanes;
for (i = 0; i < planes; i++) {
struct v4l2_plane_pix_format *plane_fmt;
unsigned int width, height, bytesperline;
plane_fmt = pixm->plane_fmt + i;
if (i == 0) {
width = pixm->width;
height = pixm->height;
} else {
width = pixm->width / xsubs;
height = pixm->height / ysubs;
}
if (stream->ispdev->isp_ver == ISP_V20 &&
stream->id == RKISP_STREAM_RAWRD2 &&
fmt->fmt_type == FMT_BAYER)
height += RKMODULE_EXTEND_LINE;
if (stream->ispdev->isp_ver >= ISP_V20 &&
fmt->fmt_type == FMT_BAYER &&
fmt->bpp[0] != 16 &&
!stream->memory &&
stream->id != RKISP_STREAM_DMARX)
bytesperline = ALIGN(width * fmt->bpp[i] / 8, 256);
else
bytesperline = width * DIV_ROUND_UP(fmt->bpp[i], 8);
if (stream->ispdev->vicap_in.merge_num > 1)
bytesperline *= stream->ispdev->vicap_in.merge_num;
/* bytesperline from user */
if (plane_fmt->bytesperline) {
bytesperline = width * fmt->bpp[i] / 8;
if (plane_fmt->bytesperline < bytesperline) {
bytesperline = ALIGN(bytesperline, 4);
v4l2_err(&stream->ispdev->v4l2_dev,
"rawrd bytesperline:%d error, force to %d\n",
plane_fmt->bytesperline, bytesperline);
} else {
bytesperline = ALIGN(plane_fmt->bytesperline, 4);
if (bytesperline != plane_fmt->bytesperline)
v4l2_err(&stream->ispdev->v4l2_dev,
"rawrd bytesperline need 4 align, force to %d\n",
bytesperline);
}
}
plane_fmt->bytesperline = bytesperline;
plane_fmt->sizeimage = plane_fmt->bytesperline * height;
imagsize += plane_fmt->sizeimage;
}
/* convert to non-MPLANE format.
* it's important since we want to unify none-MPLANE
* and MPLANE.
*/
if (fmt->mplanes == 1)
pixm->plane_fmt[0].sizeimage = imagsize;
if (!try) {
stream->out_isp_fmt = *fmt;
stream->out_fmt = *pixm;
stream->u.dmarx.y_stride =
pixm->plane_fmt[0].bytesperline /
DIV_ROUND_UP(fmt->bpp[0], 8);
v4l2_dbg(1, rkisp_debug, &stream->ispdev->v4l2_dev,
"%s: rx:%d req(%d, %d) out(%d, %d)\n", __func__,
stream->id, pixm->width, pixm->height,
stream->out_fmt.width, stream->out_fmt.height);
}
return 0;
}
/************************* v4l2_file_operations***************************/
static const struct v4l2_file_operations rkisp_fops = {
.open = rkisp_fh_open,
.release = rkisp_fop_release,
.unlocked_ioctl = video_ioctl2,
.poll = vb2_fop_poll,
.mmap = vb2_fop_mmap,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = video_ioctl2,
#endif
};
static int rkisp_try_fmt_vid_out_mplane(struct file *file, void *fh,
struct v4l2_format *f)
{
struct rkisp_stream *stream = video_drvdata(file);
return rkisp_set_fmt(stream, &f->fmt.pix_mp, true);
}
static int rkisp_enum_fmt_vid_out_mplane(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
struct rkisp_stream *stream = video_drvdata(file);
const struct capture_fmt *fmt = NULL;
if (f->index >= stream->config->fmt_size)
return -EINVAL;
fmt = &stream->config->fmts[f->index];
f->pixelformat = fmt->fourcc;
return 0;
}
static int rkisp_s_fmt_vid_out_mplane(struct file *file,
void *priv, struct v4l2_format *f)
{
struct rkisp_stream *stream = video_drvdata(file);
struct video_device *vdev = &stream->vnode.vdev;
struct rkisp_vdev_node *node = vdev_to_node(vdev);
struct rkisp_device *dev = stream->ispdev;
if (vb2_is_busy(&node->buf_queue)) {
v4l2_err(&dev->v4l2_dev, "%s rx:%d queue busy\n",
__func__, stream->id);
return -EBUSY;
}
return rkisp_set_fmt(stream, &f->fmt.pix_mp, false);
}
static int rkisp_g_fmt_vid_out_mplane(struct file *file, void *fh,
struct v4l2_format *f)
{
struct rkisp_stream *stream = video_drvdata(file);
f->fmt.pix_mp = stream->out_fmt;
return 0;
}
static int rkisp_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct rkisp_stream *stream = video_drvdata(file);
struct device *dev = stream->ispdev->dev;
struct video_device *vdev = video_devdata(file);
strlcpy(cap->card, vdev->name, sizeof(cap->card));
snprintf(cap->driver, sizeof(cap->driver),
"%s_v%d", dev->driver->name,
stream->ispdev->isp_ver >> 4);
snprintf(cap->bus_info, sizeof(cap->bus_info),
"platform:%s", dev_name(dev));
cap->version = RKISP_DRIVER_VERSION;
return 0;
}
static long rkisp_ioctl_default(struct file *file, void *fh,
bool valid_prio, unsigned int cmd, void *arg)
{
struct rkisp_stream *stream = video_drvdata(file);
long ret = 0;
switch (cmd) {
case RKISP_CMD_GET_CSI_MEMORY_MODE:
if (stream->id != RKISP_STREAM_RAWRD0 &&
stream->id != RKISP_STREAM_RAWRD1 &&
stream->id != RKISP_STREAM_RAWRD2)
ret = -EINVAL;
else if (stream->memory == 0)
*(int *)arg = CSI_MEM_COMPACT;
else if (stream->memory == SW_CSI_RAW_WR_SIMG_MODE)
*(int *)arg = CSI_MEM_WORD_BIG_ALIGN;
else
*(int *)arg = CSI_MEM_WORD_LITTLE_ALIGN;
break;
case RKISP_CMD_SET_CSI_MEMORY_MODE:
if (stream->id != RKISP_STREAM_RAWRD0 &&
stream->id != RKISP_STREAM_RAWRD1 &&
stream->id != RKISP_STREAM_RAWRD2)
ret = -EINVAL;
else if (*(int *)arg == CSI_MEM_COMPACT)
stream->memory = 0;
else if (*(int *)arg == CSI_MEM_WORD_BIG_ALIGN)
stream->memory = SW_CSI_RAW_WR_SIMG_MODE;
else
stream->memory =
SW_CSI_RWA_WR_SIMG_SWP | SW_CSI_RAW_WR_SIMG_MODE;
break;
default:
ret = -EINVAL;
}
return ret;
}
static const struct v4l2_ioctl_ops rkisp_dmarx_ioctl = {
.vidioc_reqbufs = vb2_ioctl_reqbufs,
.vidioc_querybuf = vb2_ioctl_querybuf,
.vidioc_create_bufs = vb2_ioctl_create_bufs,
.vidioc_qbuf = vb2_ioctl_qbuf,
.vidioc_expbuf = vb2_ioctl_expbuf,
.vidioc_dqbuf = vb2_ioctl_dqbuf,
.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_try_fmt_vid_out_mplane = rkisp_try_fmt_vid_out_mplane,
.vidioc_enum_fmt_vid_out = rkisp_enum_fmt_vid_out_mplane,
.vidioc_s_fmt_vid_out_mplane = rkisp_s_fmt_vid_out_mplane,
.vidioc_g_fmt_vid_out_mplane = rkisp_g_fmt_vid_out_mplane,
.vidioc_querycap = rkisp_querycap,
.vidioc_default = rkisp_ioctl_default,
};
static void rkisp_unregister_dmarx_video(struct rkisp_stream *stream)
{
media_entity_cleanup(&stream->vnode.vdev.entity);
video_unregister_device(&stream->vnode.vdev);
}
static int rkisp_register_dmarx_video(struct rkisp_stream *stream)
{
struct rkisp_device *dev = stream->ispdev;
struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
struct video_device *vdev = &stream->vnode.vdev;
struct rkisp_vdev_node *node;
int ret = 0;
mutex_init(&stream->apilock);
node = vdev_to_node(vdev);
vdev->release = video_device_release_empty;
vdev->fops = &rkisp_fops;
vdev->minor = -1;
vdev->v4l2_dev = v4l2_dev;
vdev->lock = &stream->apilock;
video_set_drvdata(vdev, stream);
vdev->ioctl_ops = &rkisp_dmarx_ioctl;
vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE |
V4L2_CAP_STREAMING;
vdev->vfl_dir = VFL_DIR_TX;
node->pad.flags = MEDIA_PAD_FL_SOURCE;
rkisp_init_vb2_queue(&node->buf_queue, stream,
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
vdev->queue = &node->buf_queue;
ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
if (ret < 0) {
v4l2_err(v4l2_dev,
"%s failed with error %d\n", __func__, ret);
return ret;
}
ret = media_entity_pads_init(&vdev->entity, 1, &node->pad);
if (ret < 0)
goto unreg;
return 0;
unreg:
video_unregister_device(vdev);
return ret;
}
/**************** Interrupter Handler ****************/
void rkisp_dmarx_isr(u32 mis_val, struct rkisp_device *dev)
{
void __iomem *base = dev->base_addr;
struct rkisp_stream *stream;
if (mis_val & CIF_MI_DMA_READY) {
stream = &dev->dmarx_dev.stream[RKISP_STREAM_DMARX];
stream->frame_end = true;
writel(CIF_MI_DMA_READY, base + CIF_MI_ICR);
if (stream->stopping) {
stream->stopping = false;
stream->streaming = false;
wake_up(&stream->done);
} else {
dmarx_frame_end(stream);
}
}
}
void rkisp2_rawrd_isr(u32 mis_val, struct rkisp_device *dev)
{
struct rkisp_stream *stream;
int i;
for (i = RKISP_STREAM_RAWRD0; i < RKISP_MAX_DMARX_STREAM; i++) {
stream = &dev->dmarx_dev.stream[i];
if (!(mis_val & CIF_MI_FRAME(stream)))
continue;
stream->frame_end = true;
if (stream->stopping) {
stream->stopping = false;
stream->streaming = false;
wake_up(&stream->done);
} else {
dmarx_frame_end(stream);
}
}
}
static int dmarx_init(struct rkisp_device *dev, u32 id)
{
struct rkisp_dmarx_device *dmarx_dev = &dev->dmarx_dev;
struct rkisp_stream *stream;
struct video_device *vdev;
struct media_entity *source, *sink;
int ret = 0;
stream = &dmarx_dev->stream[id];
INIT_LIST_HEAD(&stream->buf_queue);
init_waitqueue_head(&stream->done);
spin_lock_init(&stream->vbq_lock);
stream->id = id;
stream->ispdev = dev;
vdev = &stream->vnode.vdev;
stream->linked = false;
switch (id) {
case RKISP_STREAM_DMARX:
strlcpy(vdev->name, DMA_VDEV_NAME,
sizeof(vdev->name));
stream->ops = &rkisp_dmarx_streams_ops;
stream->config = &rkisp_dmarx_stream_config;
break;
case RKISP_STREAM_RAWRD0:
strlcpy(vdev->name, DMARX0_VDEV_NAME,
sizeof(vdev->name));
stream->ops = &rkisp2_dmarx_streams_ops;
stream->config = &rkisp2_dmarx0_stream_config;
break;
case RKISP_STREAM_RAWRD1:
strlcpy(vdev->name, DMARX1_VDEV_NAME,
sizeof(vdev->name));
stream->ops = &rkisp2_dmarx_streams_ops;
stream->config = &rkisp2_dmarx1_stream_config;
break;
case RKISP_STREAM_RAWRD2:
strlcpy(vdev->name, DMARX2_VDEV_NAME,
sizeof(vdev->name));
stream->ops = &rkisp2_dmarx_streams_ops;
stream->config = &rkisp2_dmarx2_stream_config;
break;
default:
v4l2_err(&dev->v4l2_dev, "Invalid dmarx\n");
return -EINVAL;
}
ret = rkisp_register_dmarx_video(stream);
if (ret < 0)
return ret;
/* dmarx link -> isp subdev */
source = &vdev->entity;
sink = &dev->isp_sdev.sd.entity;
return media_create_pad_link(source, 0, sink,
RKISP_ISP_PAD_SINK, stream->linked);
}
void rkisp_dmarx_set_fmt(struct rkisp_stream *stream,
struct v4l2_pix_format_mplane pixm)
{
rkisp_set_fmt(stream, &pixm, false);
}
void rkisp_rawrd_set_pic_size(struct rkisp_device *dev,
u32 width, u32 height)
{
struct rkisp_isp_subdev *sdev = &dev->isp_sdev;
u8 mult = sdev->in_fmt.fmt_type == FMT_YUV ? 2 : 1;
u32 w, h;
/* rx height should equal to isp height + offset for read back mode */
height = sdev->in_crop.top + sdev->in_crop.height;
w = width;
h = height;
if (dev->unite_div > ISP_UNITE_DIV1)
w = width / 2 + RKMOUDLE_UNITE_EXTEND_PIXEL;
if (dev->unite_div == ISP_UNITE_DIV4)
h = height / 2 + RKMOUDLE_UNITE_EXTEND_PIXEL;
/* isp20 extend line for normal read back mode to fix internal bug */
if (dev->isp_ver == ISP_V20 &&
sdev->in_fmt.fmt_type == FMT_BAYER &&
sdev->out_fmt.fmt_type != FMT_BAYER &&
dev->rd_mode == HDR_RDBK_FRAME1)
h += RKMODULE_EXTEND_LINE;
w *= mult;
rkisp_unite_write(dev, CSI2RX_RAW_RD_PIC_SIZE, h << 16 | w, false);
}
void rkisp_dmarx_get_frame(struct rkisp_device *dev, u32 *id,
u64 *sof_timestamp, u64 *timestamp,
bool sync)
{
unsigned long flag = 0;
u64 sof_time = 0, frame_timestamp = 0;
u32 frame_id = 0;
if (!IS_HDR_RDBK(dev->rd_mode)) {
frame_id = atomic_read(&dev->isp_sdev.frm_sync_seq) - 1;
frame_timestamp = dev->isp_sdev.frm_timestamp;
goto end;
}
spin_lock_irqsave(&dev->rdbk_lock, flag);
if (sync) {
frame_id = dev->dmarx_dev.cur_frame.id;
sof_time = dev->dmarx_dev.cur_frame.sof_timestamp;
frame_timestamp = dev->dmarx_dev.cur_frame.timestamp;
} else {
frame_id = dev->dmarx_dev.pre_frame.id;
sof_time = dev->dmarx_dev.pre_frame.sof_timestamp;
frame_timestamp = dev->dmarx_dev.pre_frame.timestamp;
}
spin_unlock_irqrestore(&dev->rdbk_lock, flag);
end:
if (id)
*id = frame_id;
if (sof_timestamp)
*sof_timestamp = sof_time;
if (timestamp)
*timestamp = frame_timestamp;
}
int rkisp_register_dmarx_vdev(struct rkisp_device *dev)
{
struct rkisp_dmarx_device *dmarx_dev = &dev->dmarx_dev;
int ret = 0;
memset(dmarx_dev, 0, sizeof(*dmarx_dev));
dmarx_dev->ispdev = dev;
#ifdef RKISP_DMAREAD_EN
ret = dmarx_init(dev, RKISP_STREAM_DMARX);
if (ret < 0)
goto err;
#endif
if (dev->isp_ver >= ISP_V20) {
ret = dmarx_init(dev, RKISP_STREAM_RAWRD0);
if (ret < 0)
goto err_free_dmarx;
ret = dmarx_init(dev, RKISP_STREAM_RAWRD2);
if (ret < 0)
goto err_free_dmarx0;
}
if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V30) {
ret = dmarx_init(dev, RKISP_STREAM_RAWRD1);
if (ret < 0)
goto err_free_dmarx2;
}
return 0;
err_free_dmarx2:
rkisp_unregister_dmarx_video(&dmarx_dev->stream[RKISP_STREAM_RAWRD2]);
err_free_dmarx0:
rkisp_unregister_dmarx_video(&dmarx_dev->stream[RKISP_STREAM_RAWRD0]);
err_free_dmarx:
#ifdef RKISP_DMAREAD_EN
rkisp_unregister_dmarx_video(&dmarx_dev->stream[RKISP_STREAM_DMARX]);
err:
#endif
return ret;
}
void rkisp_unregister_dmarx_vdev(struct rkisp_device *dev)
{
struct rkisp_dmarx_device *dmarx_dev = &dev->dmarx_dev;
struct rkisp_stream *stream;
#ifdef RKISP_DMAREAD_EN
stream = &dmarx_dev->stream[RKISP_STREAM_DMARX];
rkisp_unregister_dmarx_video(stream);
#endif
if (dev->isp_ver >= ISP_V20) {
stream = &dmarx_dev->stream[RKISP_STREAM_RAWRD0];
rkisp_unregister_dmarx_video(stream);
stream = &dmarx_dev->stream[RKISP_STREAM_RAWRD2];
rkisp_unregister_dmarx_video(stream);
}
if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V30) {
stream = &dmarx_dev->stream[RKISP_STREAM_RAWRD1];
rkisp_unregister_dmarx_video(stream);
}
}