diff --git a/drivers/media/platform/rockchip/isp1/Makefile b/drivers/media/platform/rockchip/isp1/Makefile index 5fe250336de9..788e3d97978a 100644 --- a/drivers/media/platform/rockchip/isp1/Makefile +++ b/drivers/media/platform/rockchip/isp1/Makefile @@ -6,4 +6,5 @@ video_rkisp1-objs += rkisp1.o \ regs.o \ isp_stats.o \ isp_params.o \ - capture.o + capture.o \ + dmarx.o diff --git a/drivers/media/platform/rockchip/isp1/capture.c b/drivers/media/platform/rockchip/isp1/capture.c index 24b30d47c130..81fd10bea419 100644 --- a/drivers/media/platform/rockchip/isp1/capture.c +++ b/drivers/media/platform/rockchip/isp1/capture.c @@ -86,7 +86,7 @@ * @xsubs: horizontal color samples in a 4*4 matrix, for yuv * @ysubs: vertical color samples in a 4*4 matrix, for yuv */ -static int fcc_xysubs(u32 fcc, u32 *xsubs, u32 *ysubs) +int fcc_xysubs(u32 fcc, u32 *xsubs, u32 *ysubs) { switch (fcc) { case V4L2_PIX_FMT_GREY: @@ -915,15 +915,12 @@ static int raw_config_mi(struct rkisp1_stream *stream) { void __iomem *base = stream->ispdev->base_addr; struct rkisp1_device *dev = stream->ispdev; - struct v4l2_mbus_framefmt *in_frm = - &dev->active_sensor->fmt.format; + struct v4l2_mbus_framefmt *in_frm; u32 in_size; - v4l2_dbg(1, rkisp1_debug, &dev->v4l2_dev, - "stream:%d input %dx%d\n", - stream->id, in_frm->width, in_frm->height); - - if (dev->active_sensor->mbus.type != V4L2_MBUS_CSI2) { + if (!dev->active_sensor || + (dev->active_sensor && + dev->active_sensor->mbus.type != V4L2_MBUS_CSI2)) { if (stream->id == RKISP1_STREAM_RAW) v4l2_err(&dev->v4l2_dev, "only mipi sensor support raw path\n"); @@ -933,6 +930,12 @@ static int raw_config_mi(struct rkisp1_stream *stream) if (dev->stream[RKISP1_STREAM_RAW].streaming) return 0; + in_frm = &dev->active_sensor->fmt.format; + + v4l2_dbg(1, rkisp1_debug, &dev->v4l2_dev, + "stream:%d input %dx%d\n", + stream->id, in_frm->width, in_frm->height); + /* raw output size equal to sensor input size */ if (stream->id == RKISP1_STREAM_RAW) { in_size = stream->out_fmt.plane_fmt[0].sizeimage; @@ -1183,7 +1186,8 @@ static void rkisp1_stream_stop(struct rkisp1_stream *stream) stream->stopping = true; stream->ops->stop_mi(stream); - if (dev->isp_state == ISP_START) { + if (dev->isp_state == ISP_START && + dev->isp_inp != INP_DMARX_ISP) { ret = wait_event_timeout(stream->done, !stream->streaming, msecs_to_jiffies(1000)); @@ -1382,9 +1386,10 @@ static int rkisp1_create_dummy_buf(struct rkisp1_stream *stream) stream->out_fmt.height, stream->out_fmt.plane_fmt[1].sizeimage, stream->out_fmt.plane_fmt[2].sizeimage); - if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2 && - (dev->isp_ver == ISP_V12 || - dev->isp_ver == ISP_V13)) { + if (dev->active_sensor && + dev->active_sensor->mbus.type == V4L2_MBUS_CSI2 && + (dev->isp_ver == ISP_V12 || + dev->isp_ver == ISP_V13)) { u32 in_size; struct rkisp1_stream *raw = &dev->stream[RKISP1_STREAM_RAW]; @@ -1504,7 +1509,8 @@ rkisp1_start_streaming(struct vb2_queue *queue, unsigned int count) if (WARN_ON(stream->streaming)) return -EBUSY; - if (!dev->active_sensor) { + if (!dev->active_sensor && + dev->isp_inp != INP_DMARX_ISP) { ret = rkisp1_update_sensor_info(dev); if (ret < 0) { v4l2_err(v4l2_dev, @@ -1734,7 +1740,7 @@ static void rkisp1_dma_detach_device(struct rkisp1_device *rkisp1_dev) iommu_detach_device(domain, dev); } -static int rkisp1_fh_open(struct file *filp) +int rkisp1_fh_open(struct file *filp) { struct rkisp1_stream *stream = video_drvdata(filp); struct rkisp1_device *dev = stream->ispdev; @@ -1749,7 +1755,7 @@ static int rkisp1_fh_open(struct file *filp) return ret; } -static int rkisp1_fop_release(struct file *file) +int rkisp1_fop_release(struct file *file) { struct rkisp1_stream *stream = video_drvdata(file); struct rkisp1_device *dev = stream->ispdev; @@ -2132,6 +2138,9 @@ void rkisp1_mi_isr(u32 mis_val, struct rkisp1_device *dev) { unsigned int i; + if (mis_val & CIF_MI_DMA_READY) + rkisp1_dmarx_isr(mis_val, dev); + for (i = 0; i < ARRAY_SIZE(dev->stream); ++i) { struct rkisp1_stream *stream = &dev->stream[i]; diff --git a/drivers/media/platform/rockchip/isp1/capture.h b/drivers/media/platform/rockchip/isp1/capture.h index f7249b240981..8613618352e9 100644 --- a/drivers/media/platform/rockchip/isp1/capture.h +++ b/drivers/media/platform/rockchip/isp1/capture.h @@ -92,6 +92,10 @@ struct rkisp1_stream_raw { u8 pre_stop; }; +struct rkisp1_stream_dmarx { + int y_stride; +}; + /* Different config between selfpath and mainpath */ struct stream_config { const struct capture_fmt *fmts; @@ -191,12 +195,14 @@ struct rkisp1_stream { struct rkisp1_buffer *next_buf; bool streaming; bool stopping; + bool frame_end; wait_queue_head_t done; unsigned int burst; union { struct rkisp1_stream_sp sp; struct rkisp1_stream_mp mp; struct rkisp1_stream_raw raw; + struct rkisp1_stream_dmarx dmarx; } u; }; @@ -207,5 +213,7 @@ void rkisp1_stream_init(struct rkisp1_device *dev, u32 id); void rkisp1_set_stream_def_fmt(struct rkisp1_device *dev, u32 id, u32 width, u32 height, u32 pixelformat); void rkisp1_mipi_dmatx0_end(u32 status, struct rkisp1_device *dev); - +int fcc_xysubs(u32 fcc, u32 *xsubs, u32 *ysubs); +int rkisp1_fh_open(struct file *filp); +int rkisp1_fop_release(struct file *file); #endif /* _RKISP1_PATH_VIDEO_H */ diff --git a/drivers/media/platform/rockchip/isp1/dev.c b/drivers/media/platform/rockchip/isp1/dev.c index ce10bc36cf56..dd9634ebfcde 100644 --- a/drivers/media/platform/rockchip/isp1/dev.c +++ b/drivers/media/platform/rockchip/isp1/dev.c @@ -92,6 +92,9 @@ static int __isp_pipeline_prepare(struct rkisp1_pipeline *p, p->num_subdevs = 0; memset(p->subdevs, 0, sizeof(p->subdevs)); + if (dev->isp_inp == INP_DMARX_ISP) + return 0; + while (1) { struct media_pad *pad = NULL; @@ -117,6 +120,10 @@ static int __isp_pipeline_prepare(struct rkisp1_pipeline *p, if (me->num_pads == 1) break; } + + if (!p->num_subdevs) + return -EINVAL; + return 0; } @@ -169,6 +176,11 @@ static int __isp_pipeline_s_isp_clk(struct rkisp1_pipeline *p) u64 data_rate; int i; + if (dev->isp_inp == INP_DMARX_ISP) { + clk_set_rate(dev->clks[0], 400 * 1000000UL); + return 0; + } + /* find the subdev of active sensor */ sd = p->subdevs[0]; for (i = 0; i < p->num_subdevs; i++) { @@ -221,11 +233,11 @@ static int rkisp1_pipeline_open(struct rkisp1_pipeline *p, return 0; /* go through media graphic and get subdevs */ - if (prepare) - __isp_pipeline_prepare(p, me); - - if (!p->num_subdevs) - return -EINVAL; + if (prepare) { + ret = __isp_pipeline_prepare(p, me); + if (ret < 0) + return ret; + } ret = __isp_pipeline_s_isp_clk(p); if (ret < 0) @@ -594,10 +606,14 @@ static int rkisp1_register_platform_subdevs(struct rkisp1_device *dev) if (ret < 0) goto err_unreg_isp_subdev; - ret = rkisp1_register_stats_vdev(&dev->stats_vdev, &dev->v4l2_dev, dev); + ret = rkisp1_register_dmarx_vdev(dev); if (ret < 0) goto err_unreg_stream_vdev; + ret = rkisp1_register_stats_vdev(&dev->stats_vdev, &dev->v4l2_dev, dev); + if (ret < 0) + goto err_unreg_dmarx_vdev; + ret = rkisp1_register_params_vdev(&dev->params_vdev, &dev->v4l2_dev, dev); if (ret < 0) @@ -615,6 +631,8 @@ err_unreg_params_vdev: rkisp1_unregister_params_vdev(&dev->params_vdev); err_unreg_stats_vdev: rkisp1_unregister_stats_vdev(&dev->stats_vdev); +err_unreg_dmarx_vdev: + rkisp1_unregister_dmarx_vdev(dev); err_unreg_stream_vdev: rkisp1_unregister_stream_vdevs(dev); err_unreg_isp_subdev: diff --git a/drivers/media/platform/rockchip/isp1/dev.h b/drivers/media/platform/rockchip/isp1/dev.h index 1fb19b791874..d4baceed384a 100644 --- a/drivers/media/platform/rockchip/isp1/dev.h +++ b/drivers/media/platform/rockchip/isp1/dev.h @@ -36,6 +36,7 @@ #define _RKISP1_DEV_H #include "capture.h" +#include "dmarx.h" #include "rkisp1.h" #include "isp_params.h" #include "isp_stats.h" @@ -52,6 +53,7 @@ #define GRP_ID_ISP BIT(2) #define GRP_ID_ISP_MP BIT(3) #define GRP_ID_ISP_SP BIT(4) +#define GRP_ID_ISP_DMARX BIT(5) #define RKISP1_MAX_BUS_CLK 8 #define RKISP1_MAX_SENSOR 2 @@ -77,6 +79,13 @@ enum rkisp1_isp_state { ISP_ERROR }; +enum rkisp1_isp_inp { + INP_INVAL = 0, + INP_CSI, + INP_DVP, + INP_DMARX_ISP, +}; + /* * struct rkisp1_pipeline - An ISP hardware pipeline * @@ -138,6 +147,7 @@ struct rkisp1_device { struct rkisp1_stream stream[RKISP1_MAX_STREAM]; struct rkisp1_isp_stats_vdev stats_vdev; struct rkisp1_isp_params_vdev params_vdev; + struct rkisp1_dmarx_device dmarx_dev; struct rkisp1_pipeline pipe; struct vb2_alloc_ctx *alloc_ctx; struct iommu_domain *domain; @@ -154,6 +164,7 @@ struct rkisp1_device { struct v4l2_subdev *hdr_sensor; enum rkisp1_isp_state isp_state; unsigned int isp_err_cnt; + enum rkisp1_isp_inp isp_inp; }; #endif diff --git a/drivers/media/platform/rockchip/isp1/dmarx.c b/drivers/media/platform/rockchip/isp1/dmarx.c new file mode 100644 index 000000000000..8a7373e99148 --- /dev/null +++ b/drivers/media/platform/rockchip/isp1/dmarx.c @@ -0,0 +1,700 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dev.h" +#include "regs.h" + +#define CIF_ISP_REQ_BUFS_MIN 1 + +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 struct stream_config rkisp1_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 const +struct capture_fmt *find_fmt(struct rkisp1_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 rkisp1_stream *stream) +{ + struct rkisp1_device *dev = stream->ispdev; + void __iomem *base = dev->base_addr; + struct capture_fmt *dmarx_in_fmt = &stream->out_isp_fmt; + + v4l2_dbg(1, rkisp1_debug, &dev->v4l2_dev, + "%s %dx%x 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 rkisp1_stream *stream) +{ + void __iomem *base = stream->ispdev->base_addr; + + if (stream->curr_buf) { + mi_set_y_addr(stream, + stream->curr_buf->buff_addr[RKISP1_PLANE_Y]); + mi_set_cb_addr(stream, + stream->curr_buf->buff_addr[RKISP1_PLANE_CB]); + mi_set_cr_addr(stream, + stream->curr_buf->buff_addr[RKISP1_PLANE_CR]); + mi_dmarx_start(base); + stream->frame_end = false; + } +} + +static void dmarx_stop_mi(struct rkisp1_stream *stream) +{ + mi_dmarx_ready_disable(stream); +} + +static struct streams_ops rkisp1_dmarx_streams_ops = { + .config_mi = dmarx_config_mi, + .stop_mi = dmarx_stop_mi, + .update_mi = update_dmarx, +}; + +static int dmarx_frame_end(struct rkisp1_stream *stream) +{ + unsigned long lock_flags = 0; + + if (stream->curr_buf) { + vb2_buffer_done(&stream->curr_buf->vb.vb2_buf, + VB2_BUF_STATE_DONE); + stream->curr_buf = NULL; + } + + spin_lock_irqsave(&stream->vbq_lock, lock_flags); + if (!list_empty(&stream->buf_queue)) { + stream->curr_buf = + list_first_entry(&stream->buf_queue, + struct rkisp1_buffer, + queue); + list_del(&stream->curr_buf->queue); + } + spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); + + stream->ops->update_mi(stream); + return 0; +} + +/***************************** vb2 operations*******************************/ + +static void dmarx_stop(struct rkisp1_stream *stream) +{ + struct rkisp1_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) { + ret = wait_event_timeout(stream->done, + !stream->streaming, + msecs_to_jiffies(500)); + 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 rkisp1_stream *stream) +{ + int ret; + + ret = stream->ops->config_mi(stream); + if (ret) + return ret; + + stream->curr_buf = NULL; + dmarx_frame_end(stream); + stream->streaming = true; + return 0; +} + +static int rkisp1_queue_setup(struct vb2_queue *queue, + const void *parg, + unsigned int *num_buffers, + unsigned int *num_planes, + unsigned int sizes[], + void *alloc_ctxs[]) +{ + struct rkisp1_stream *stream = queue->drv_priv; + struct rkisp1_device *dev = stream->ispdev; + const struct v4l2_format *pfmt = parg; + const struct v4l2_pix_format_mplane *pixm = NULL; + const struct capture_fmt *isp_fmt = NULL; + u32 i; + + if (pfmt) { + pixm = &pfmt->fmt.pix_mp; + isp_fmt = find_fmt(stream, pixm->pixelformat); + } else { + 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; + alloc_ctxs[i] = dev->alloc_ctx; + } + + v4l2_dbg(1, rkisp1_debug, &dev->v4l2_dev, "%s count %d, size %d\n", + v4l2_type_names[queue->type], *num_buffers, sizes[0]); + + return 0; +} + +/* + * The vb2_buffer are stored in rkisp1_buffer, in order to unify + * mplane buffer and none-mplane buffer. + */ +static void rkisp1_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct rkisp1_buffer *ispbuf = to_rkisp1_buffer(vbuf); + struct vb2_queue *queue = vb->vb2_queue; + struct rkisp1_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; + int i; + + memset(ispbuf->buff_addr, 0, sizeof(ispbuf->buff_addr)); + for (i = 0; i < isp_fmt->mplanes; i++) + 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; + } + } + + 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 dmarx_stop_streaming(struct vb2_queue *queue) +{ + struct rkisp1_stream *stream = queue->drv_priv; + struct rkisp1_buffer *buf; + unsigned long lock_flags = 0; + + dmarx_stop(stream); + + spin_lock_irqsave(&stream->vbq_lock, lock_flags); + if (stream->curr_buf) { + 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 rkisp1_buffer, queue); + list_del(&buf->queue); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } + spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); +} + +static int dmarx_start_streaming(struct vb2_queue *queue, + unsigned int count) +{ + struct rkisp1_stream *stream = queue->drv_priv; + struct rkisp1_device *dev = stream->ispdev; + struct v4l2_device *v4l2_dev = &dev->v4l2_dev; + int ret = 0; + + if (atomic_read(&dev->open_cnt) < 2) { + v4l2_err(v4l2_dev, + "other stream should enable first\n"); + return -EINVAL; + } + + if (WARN_ON(stream->streaming)) + return -EBUSY; + + ret = dmarx_start(stream); + if (ret < 0) + v4l2_err(v4l2_dev, + "start dmarx stream:%d failed\n", + stream->id); + + return ret; +} + +static struct vb2_ops dmarx_vb2_ops = { + .queue_setup = rkisp1_queue_setup, + .buf_queue = rkisp1_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 rkisp1_stream *stream, + enum v4l2_buf_type buf_type) +{ + struct rkisp1_vdev_node *node; + + node = queue_to_node(q); + + 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 = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct rkisp1_buffer); + q->min_buffers_needed = CIF_ISP_REQ_BUFS_MIN; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &node->vlock; + + return vb2_queue_init(q); +} + +static int rkisp1_set_fmt(struct rkisp1_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 */ + 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; + } + + bytesperline = width * DIV_ROUND_UP(fmt->bpp[i], 8); + /* stride is only available for sp stream and y plane */ + if (i != 0 || + plane_fmt->bytesperline < 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, rkisp1_debug, &stream->ispdev->v4l2_dev, + "%s: stream: %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 rkisp1_fops = { + .open = rkisp1_fh_open, + .release = rkisp1_fop_release, + .unlocked_ioctl = video_ioctl2, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, +}; + +static int rkisp1_try_fmt_vid_out_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct rkisp1_stream *stream = video_drvdata(file); + + return rkisp1_set_fmt(stream, &f->fmt.pix_mp, true); +} + +static int rkisp1_enum_fmt_vid_out_mplane(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct rkisp1_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 rkisp1_s_fmt_vid_out_mplane(struct file *file, + void *priv, struct v4l2_format *f) +{ + struct rkisp1_stream *stream = video_drvdata(file); + struct video_device *vdev = &stream->vnode.vdev; + struct rkisp1_vdev_node *node = vdev_to_node(vdev); + struct rkisp1_device *dev = stream->ispdev; + + if (vb2_is_busy(&node->buf_queue)) { + v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__); + return -EBUSY; + } + + return rkisp1_set_fmt(stream, &f->fmt.pix_mp, false); +} + +static int rkisp1_g_fmt_vid_out_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct rkisp1_stream *stream = video_drvdata(file); + + f->fmt.pix_mp = stream->out_fmt; + + return 0; +} + +static int rkisp1_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct rkisp1_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)); + + return 0; +} + +static const struct v4l2_ioctl_ops rkisp1_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 = rkisp1_try_fmt_vid_out_mplane, + .vidioc_enum_fmt_vid_out_mplane = rkisp1_enum_fmt_vid_out_mplane, + .vidioc_s_fmt_vid_out_mplane = rkisp1_s_fmt_vid_out_mplane, + .vidioc_g_fmt_vid_out_mplane = rkisp1_g_fmt_vid_out_mplane, + .vidioc_querycap = rkisp1_querycap, +}; + +static void rkisp1_unregister_dmarx_video(struct rkisp1_stream *stream) +{ + media_entity_cleanup(&stream->vnode.vdev.entity); + video_unregister_device(&stream->vnode.vdev); +} + +static int rkisp1_register_dmarx_video(struct rkisp1_stream *stream) +{ + struct rkisp1_device *dev = stream->ispdev; + struct v4l2_device *v4l2_dev = &dev->v4l2_dev; + struct video_device *vdev = &stream->vnode.vdev; + struct rkisp1_vdev_node *node; + int ret = 0; + + node = vdev_to_node(vdev); + mutex_init(&node->vlock); + + vdev->release = video_device_release_empty; + vdev->fops = &rkisp1_fops; + vdev->minor = -1; + vdev->v4l2_dev = v4l2_dev; + vdev->lock = &node->vlock; + video_set_drvdata(vdev, stream); + + vdev->ioctl_ops = &rkisp1_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_GRABBER, -1); + if (ret < 0) { + v4l2_err(v4l2_dev, + "video register failed with error %d\n", ret); + return ret; + } + + ret = media_entity_init(&vdev->entity, 1, &node->pad, 0); + if (ret < 0) + goto unreg; + + return 0; +unreg: + video_unregister_device(vdev); + return ret; +} + +/**************** Interrupter Handler ****************/ + +void rkisp1_dmarx_isr(u32 mis_val, struct rkisp1_device *dev) +{ + void __iomem *base = dev->base_addr; + struct rkisp1_stream *stream; + + if (mis_val & CIF_MI_DMA_READY) { + stream = &dev->dmarx_dev.stream[RKISP1_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); + } + } +} + +int rkisp1_register_dmarx_vdev(struct rkisp1_device *dev) +{ + struct rkisp1_dmarx_device *dmarx_dev = &dev->dmarx_dev; + struct rkisp1_stream *stream; + struct video_device *vdev; + struct media_entity *source, *sink; + int ret = 0; + + memset(dmarx_dev, 0, sizeof(*dmarx_dev)); + dmarx_dev->ispdev = dev; + + if (dev->isp_ver <= ISP_V13) { + stream = &dmarx_dev->stream[RKISP1_STREAM_DMARX]; + INIT_LIST_HEAD(&stream->buf_queue); + init_waitqueue_head(&stream->done); + spin_lock_init(&stream->vbq_lock); + stream->id = RKISP1_STREAM_DMARX; + stream->ispdev = dev; + stream->ops = &rkisp1_dmarx_streams_ops; + stream->config = &rkisp1_dmarx_stream_config; + vdev = &stream->vnode.vdev; + strlcpy(vdev->name, DMA_VDEV_NAME, sizeof(vdev->name)); + ret = rkisp1_register_dmarx_video(stream); + if (ret < 0) + return ret; + + /* dmarx links -> isp subdev */ + source = &vdev->entity; + sink = &dev->isp_sdev.sd.entity; + media_entity_create_link(source, 0, + sink, RKISP1_ISP_PAD_SINK, 0); + } + + return ret; +} + +void rkisp1_unregister_dmarx_vdev(struct rkisp1_device *dev) +{ + struct rkisp1_dmarx_device *dmarx_dev = &dev->dmarx_dev; + struct rkisp1_stream *stream; + + if (dev->isp_ver <= ISP_V13) { + stream = &dmarx_dev->stream[RKISP1_STREAM_DMARX]; + rkisp1_unregister_dmarx_video(stream); + } +} diff --git a/drivers/media/platform/rockchip/isp1/dmarx.h b/drivers/media/platform/rockchip/isp1/dmarx.h new file mode 100644 index 000000000000..abc3b39aa0b5 --- /dev/null +++ b/drivers/media/platform/rockchip/isp1/dmarx.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */ + +#ifndef _RKISP1_DMARX_H +#define _RKISP1_DMARX_H + +#include "capture.h" +#include "common.h" + +#define RKISP1_STREAM_DMARX 0 +#define RKISP1_MAX_DMARX_STREAM 1 + +struct rkisp1_dmarx_device; + +enum rkisp1_dmarx_pad { + RKISP1_DMARX_PAD_SINK, + RKISP1_DMARX_PAD_SOURCE, + RKISP1_DMARX_PAD_MAX +}; + +struct rkisp1_dmarx_device { + struct rkisp1_device *ispdev; + struct rkisp1_stream stream[RKISP1_MAX_DMARX_STREAM]; +}; + +void rkisp1_dmarx_isr(u32 mis_val, struct rkisp1_device *dev); +void rkisp1_unregister_dmarx_vdev(struct rkisp1_device *dev); +int rkisp1_register_dmarx_vdev(struct rkisp1_device *dev); +#endif /* _RKISP1_DMARX_H */ diff --git a/drivers/media/platform/rockchip/isp1/regs.h b/drivers/media/platform/rockchip/isp1/regs.h index 37430d9d79f7..d31ef1b127f5 100644 --- a/drivers/media/platform/rockchip/isp1/regs.h +++ b/drivers/media/platform/rockchip/isp1/regs.h @@ -91,6 +91,8 @@ #define CIF_ISP_ACQ_PROP_IN_SEL_10B_MSB (2 << 12) #define CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO (3 << 12) #define CIF_ISP_ACQ_PROP_IN_SEL_8B_MSB (4 << 12) +#define CIF_ISP_ACQ_PROP_DMA_RGB BIT(15) +#define CIF_ISP_ACQ_PROP_DMA_YUV BIT(16) /* VI_DPCL */ #define CIF_VI_DPCL_DMA_JPEG (0 << 0) @@ -232,17 +234,17 @@ #define CIF_MI_STATUS_SP_Y_FIFO_FULL BIT(4) /* MI_DMA_CTRL */ -#define CIF_MI_DMA_CTRL_BURST_LEN_LUM_16 (0 << 0) -#define CIF_MI_DMA_CTRL_BURST_LEN_LUM_32 (1 << 0) -#define CIF_MI_DMA_CTRL_BURST_LEN_LUM_64 (2 << 0) -#define CIF_MI_DMA_CTRL_BURST_LEN_CHROM_16 (0 << 2) -#define CIF_MI_DMA_CTRL_BURST_LEN_CHROM_32 (1 << 2) -#define CIF_MI_DMA_CTRL_BURST_LEN_CHROM_64 (2 << 2) +#define CIF_MI_DMA_CTRL_BURST_LEN_LUM_4 (0 << 0) +#define CIF_MI_DMA_CTRL_BURST_LEN_LUM_8 BIT(0) +#define CIF_MI_DMA_CTRL_BURST_LEN_LUM_16 BIT(1) +#define CIF_MI_DMA_CTRL_BURST_LEN_CHROM_4 (0 << 2) +#define CIF_MI_DMA_CTRL_BURST_LEN_CHROM_8 BIT(2) +#define CIF_MI_DMA_CTRL_BURST_LEN_CHROM_16 BIT(3) #define CIF_MI_DMA_CTRL_READ_FMT_PLANAR (0 << 4) #define CIF_MI_DMA_CTRL_READ_FMT_SPLANAR (1 << 4) +#define CIF_MI_DMA_CTRL_READ_FMT_PACKED (2 << 4) #define CIF_MI_DMA_CTRL_FMT_YUV400 (0 << 6) #define CIF_MI_DMA_CTRL_FMT_YUV420 (1 << 6) -#define CIF_MI_DMA_CTRL_READ_FMT_PACKED (2 << 4) #define CIF_MI_DMA_CTRL_FMT_YUV422 (2 << 6) #define CIF_MI_DMA_CTRL_FMT_YUV444 (3 << 6) #define CIF_MI_DMA_CTRL_BYTE_SWAP BIT(8) @@ -1941,4 +1943,52 @@ static inline void mi_ctrl2(void __iomem *base, u32 val) writel(val, base + CIF_MI_CTRL2); } +static inline void mi_dmarx_ready_enable(struct rkisp1_stream *stream) +{ + void __iomem *base = stream->ispdev->base_addr; + void __iomem *addr = base + CIF_MI_IMSC; + + writel(CIF_MI_DMA_READY | readl(addr), addr); +} + +static inline void mi_dmarx_ready_disable(struct rkisp1_stream *stream) +{ + void __iomem *base = stream->ispdev->base_addr; + void __iomem *addr = base + CIF_MI_IMSC; + + writel(~CIF_MI_DMA_READY & readl(addr), addr); +} + +static inline void dmarx_set_uv_swap(void __iomem *base) +{ + void __iomem *addr = base + CIF_MI_XTD_FORMAT_CTRL; + u32 reg = readl(addr) & ~BIT(2); + + writel(reg | CIF_MI_XTD_FMT_CTRL_DMA_CB_CR_SWAP, addr); +} + +static inline void dmarx_set_y_width(void __iomem *base, u32 val) +{ + writel(val, base + CIF_MI_DMA_Y_PIC_WIDTH); +} + +static inline void dmarx_set_y_line_length(void __iomem *base, u32 val) +{ + writel(val, base + CIF_MI_DMA_Y_LLENGTH); +} + +static inline void dmarx_ctrl(void __iomem *base, u32 val) +{ + void __iomem *addr = base + CIF_MI_DMA_CTRL; + + writel(val | readl(addr), addr); +} + +static inline void mi_dmarx_start(void __iomem *base) +{ + void __iomem *addr = base + CIF_MI_DMA_START; + + writel(CIF_MI_DMA_START_ENABLE, addr); +} + #endif /* _RKISP1_REGS_H */ diff --git a/drivers/media/platform/rockchip/isp1/rkisp1.c b/drivers/media/platform/rockchip/isp1/rkisp1.c index e7d61e3b2f80..eaeb8368a8c0 100644 --- a/drivers/media/platform/rockchip/isp1/rkisp1.c +++ b/drivers/media/platform/rockchip/isp1/rkisp1.c @@ -254,6 +254,7 @@ static int rkisp1_config_isp(struct rkisp1_device *dev) u32 irq_mask = 0; u32 signal = 0; u32 acq_mult = 0; + u32 acq_prop = 0; sensor = dev->active_sensor; in_frm = &dev->isp_sdev.in_frm; @@ -265,7 +266,7 @@ static int rkisp1_config_isp(struct rkisp1_device *dev) if (in_fmt->fmt_type == FMT_BAYER) { acq_mult = 1; if (out_fmt->fmt_type == FMT_BAYER) { - if (sensor->mbus.type == V4L2_MBUS_BT656) + if (sensor && sensor->mbus.type == V4L2_MBUS_BT656) isp_ctrl = CIF_ISP_CTRL_ISP_MODE_RAW_PICT_ITU656; else @@ -283,17 +284,20 @@ static int rkisp1_config_isp(struct rkisp1_device *dev) writel(CIF_ISP_DEMOSAIC_TH(0xc), base + CIF_ISP_DEMOSAIC); - if (sensor->mbus.type == V4L2_MBUS_BT656) + if (sensor && sensor->mbus.type == V4L2_MBUS_BT656) isp_ctrl = CIF_ISP_CTRL_ISP_MODE_BAYER_ITU656; else isp_ctrl = CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601; } + + if (dev->isp_inp == INP_DMARX_ISP) + acq_prop = CIF_ISP_ACQ_PROP_DMA_RGB; } else if (in_fmt->fmt_type == FMT_YUV) { acq_mult = 2; - if (sensor->mbus.type == V4L2_MBUS_CSI2) { + if (sensor && sensor->mbus.type == V4L2_MBUS_CSI2) { isp_ctrl = CIF_ISP_CTRL_ISP_MODE_ITU601; } else { - if (sensor->mbus.type == V4L2_MBUS_BT656) + if (sensor && sensor->mbus.type == V4L2_MBUS_BT656) isp_ctrl = CIF_ISP_CTRL_ISP_MODE_ITU656; else isp_ctrl = CIF_ISP_CTRL_ISP_MODE_ITU601; @@ -301,17 +305,19 @@ static int rkisp1_config_isp(struct rkisp1_device *dev) } irq_mask |= CIF_ISP_DATA_LOSS; + if (dev->isp_inp == INP_DMARX_ISP) + acq_prop = CIF_ISP_ACQ_PROP_DMA_YUV; } /* Set up input acquisition properties */ - if (sensor->mbus.type == V4L2_MBUS_BT656 || - sensor->mbus.type == V4L2_MBUS_PARALLEL) { + if (sensor && (sensor->mbus.type == V4L2_MBUS_BT656 || + sensor->mbus.type == V4L2_MBUS_PARALLEL)) { if (sensor->mbus.flags & V4L2_MBUS_PCLK_SAMPLE_RISING) signal = CIF_ISP_ACQ_PROP_POS_EDGE; } - if (sensor->mbus.type == V4L2_MBUS_PARALLEL) { + if (sensor && sensor->mbus.type == V4L2_MBUS_PARALLEL) { if (sensor->mbus.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) signal |= CIF_ISP_ACQ_PROP_VSYNC_LOW; @@ -320,9 +326,10 @@ static int rkisp1_config_isp(struct rkisp1_device *dev) } writel(isp_ctrl, base + CIF_ISP_CTRL); - writel(signal | in_fmt->yuv_seq | - CIF_ISP_ACQ_PROP_BAYER_PAT(in_fmt->bayer_pat) | - CIF_ISP_ACQ_PROP_FIELD_SEL_ALL, base + CIF_ISP_ACQ_PROP); + acq_prop |= signal | in_fmt->yuv_seq | + CIF_ISP_ACQ_PROP_BAYER_PAT(in_fmt->bayer_pat) | + CIF_ISP_ACQ_PROP_FIELD_SEL_ALL; + writel(acq_prop, base + CIF_ISP_ACQ_PROP); writel(0, base + CIF_ISP_ACQ_NR_FRAMES); /* Acquisition Size */ @@ -551,13 +558,17 @@ static int rkisp1_config_path(struct rkisp1_device *dev) struct rkisp1_sensor_info *sensor = dev->active_sensor; u32 dpcl = readl(dev->base_addr + CIF_VI_DPCL); - if (sensor->mbus.type == V4L2_MBUS_BT656 || - sensor->mbus.type == V4L2_MBUS_PARALLEL) { + if (sensor && (sensor->mbus.type == V4L2_MBUS_BT656 || + sensor->mbus.type == V4L2_MBUS_PARALLEL)) { ret = rkisp1_config_dvp(dev); dpcl |= CIF_VI_DPCL_IF_SEL_PARALLEL; - } else if (sensor->mbus.type == V4L2_MBUS_CSI2) { + dev->isp_inp = INP_DVP; + } else if (sensor && sensor->mbus.type == V4L2_MBUS_CSI2) { ret = rkisp1_config_mipi(dev); dpcl |= CIF_VI_DPCL_IF_SEL_MIPI; + dev->isp_inp = INP_CSI; + } else if (dev->isp_inp == INP_DMARX_ISP) { + dpcl |= CIF_VI_DPCL_DMA_SW_ISP; } writel(dpcl, dev->base_addr + CIF_VI_DPCL); @@ -712,7 +723,7 @@ static int rkisp1_isp_start(struct rkisp1_device *dev) dev->stream[RKISP1_STREAM_MP].streaming); /* Activate MIPI */ - if (sensor->mbus.type == V4L2_MBUS_CSI2) { + if (sensor && sensor->mbus.type == V4L2_MBUS_CSI2) { #if RKISP1_RK3326_USE_OLDMIPI if (dev->isp_ver == ISP_V13) { #else @@ -1369,6 +1380,24 @@ static int rkisp1_isp_sd_s_power(struct v4l2_subdev *sd, int on) return 0; } +static int rkisp1_subdev_link_setup(struct media_entity *entity, + const struct media_pad *local, + const struct media_pad *remote, + u32 flags) +{ + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + struct rkisp1_device *dev = sd_to_isp_dev(sd); + + if (!strcmp(remote->entity->name, DMA_VDEV_NAME)) { + if (flags & MEDIA_LNK_FL_ENABLED) + dev->isp_inp = INP_DMARX_ISP; + else + dev->isp_inp = INP_INVAL; + } + + return 0; +} + static int rkisp1_subdev_link_validate(struct media_link *link) { if (link->source->index == RKISP1_ISP_PAD_SINK_PARAMS) @@ -1427,6 +1456,7 @@ static const struct v4l2_subdev_pad_ops rkisp1_isp_sd_pad_ops = { }; static const struct media_entity_operations rkisp1_isp_sd_media_ops = { + .link_setup = rkisp1_subdev_link_setup, .link_validate = rkisp1_subdev_link_validate, };