v4l2: ISP/VIN support multi stream
authorliuxl0327 <liuxl0327@starfivetech.com>
Mon, 21 Mar 2022 09:37:32 +0000 (17:37 +0800)
committermason.huo <mason.huo@starfivetech.com>
Fri, 1 Jul 2022 07:05:38 +0000 (15:05 +0800)
Signed-off-by: mason.huo <mason.huo@starfivetech.com>
drivers/media/platform/starfive/v4l2_driver/stf_isp.c
drivers/media/platform/starfive/v4l2_driver/stf_isp.h
drivers/media/platform/starfive/v4l2_driver/stf_video.c [changed mode: 0755->0644]
drivers/media/platform/starfive/v4l2_driver/stf_video.h
drivers/media/platform/starfive/v4l2_driver/stf_vin.c
drivers/media/platform/starfive/v4l2_driver/stf_vin.h
drivers/media/platform/starfive/v4l2_driver/stf_vin_hw_ops.c
drivers/media/platform/starfive/v4l2_driver/stfcamss.c
drivers/media/platform/starfive/v4l2_driver/stfcamss.h

index 70a0dde..93bacaf 100644 (file)
@@ -28,7 +28,6 @@ int stf_isp_subdev_init(struct stfcamss *stfcamss, int id)
 {
        struct stf_isp_dev *isp_dev = &stfcamss->isp_dev[id];
 
-       atomic_set(&isp_dev->ref_count, 0);
        isp_dev->sdev_type = id == 0 ? ISP0_DEV_TYPE : ISP1_DEV_TYPE;
        isp_dev->id = id;
        isp_dev->hw_ops = &isp_ops;
@@ -36,6 +35,7 @@ int stf_isp_subdev_init(struct stfcamss *stfcamss, int id)
        isp_dev->formats = isp_formats_st7110;
        isp_dev->nformats = ARRAY_SIZE(isp_formats_st7110);
        mutex_init(&isp_dev->stream_lock);
+       mutex_init(&isp_dev->power_lock);
        mutex_init(&isp_dev->setfile_lock);
        atomic_set(&isp_dev->shadow_count, 0);
        return 0;
@@ -198,8 +198,12 @@ static int isp_s_ctrl(struct v4l2_ctrl *ctrl)
         * not apply any controls to H/W at this time. Instead
         * the controls will be restored right after power-up.
         */
-       if (!atomic_read(&isp_dev->ref_count))
+       mutex_lock(&isp_dev->power_lock);
+       if (isp_dev->power_count == 0) {
+               mutex_unlock(&isp_dev->power_lock);
                return 0;
+       }
+       mutex_unlock(&isp_dev->power_lock);
 
        switch (ctrl->id) {
        case V4L2_CID_AUTOGAIN:
@@ -325,11 +329,27 @@ free_ctrls:
 static int isp_set_power(struct v4l2_subdev *sd, int on)
 {
        struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
+       struct stf_vin2_dev *vin_dev = isp_dev->stfcamss->vin_dev;
 
-       if (on)
-               atomic_inc(&isp_dev->ref_count);
-       else
-               atomic_dec(&isp_dev->ref_count);
+       st_debug(ST_ISP, "%s, %d\n", __func__, __LINE__);
+       mutex_lock(&isp_dev->power_lock);
+       if (on) {
+               if (isp_dev->power_count == 0) {
+                       vin_dev->hw_ops->vin_clk_enable(vin_dev);
+                       isp_dev->hw_ops->isp_clk_enable(isp_dev);
+                       if (!user_config_isp)
+                               isp_dev->hw_ops->isp_config_set(isp_dev);
+               }
+               isp_dev->power_count++;
+       } else {
+               if (isp_dev->power_count == 0)
+                       goto exit;
+               if (isp_dev->power_count == 1)
+                       isp_dev->hw_ops->isp_clk_disable(isp_dev);
+               isp_dev->power_count--;
+       }
+exit:
+       mutex_unlock(&isp_dev->power_lock);
 
        return 0;
 }
@@ -357,31 +377,31 @@ static int isp_set_stream(struct v4l2_subdev *sd, int enable)
        mutex_lock(&isp_dev->stream_lock);
        if (enable) {
                if (isp_dev->stream_count == 0) {
-                       isp_dev->hw_ops->isp_clk_enable(isp_dev);
-                       isp_dev->hw_ops->isp_reset(isp_dev);
                        isp_dev->hw_ops->isp_set_format(isp_dev,
                                        &isp_dev->crop, fmt->code);
                                // format->width, format->height);
-                       isp_dev->hw_ops->isp_config_set(isp_dev);
+                       isp_dev->hw_ops->isp_reset(isp_dev);
                        isp_dev->hw_ops->isp_stream_set(isp_dev, enable);
+                       user_config_isp = 0;
                }
                isp_dev->stream_count++;
        } else {
                if (isp_dev->stream_count == 0)
                        goto exit;
-               if (isp_dev->stream_count == 1) {
+               if (isp_dev->stream_count == 1)
                        isp_dev->hw_ops->isp_stream_set(isp_dev, enable);
-                       isp_dev->hw_ops->isp_clk_disable(isp_dev);
-               }
                isp_dev->stream_count--;
        }
 exit:
        mutex_unlock(&isp_dev->stream_lock);
 
-       if (enable && atomic_read(&isp_dev->ref_count) == 1) {
-               /* restore controls */
+       mutex_lock(&isp_dev->power_lock);
+       /* restore controls */
+       if (enable && isp_dev->power_count == 1) {
+               mutex_unlock(&isp_dev->power_lock);
                ret = v4l2_ctrl_handler_setup(&isp_dev->ctrls.handler);
-       }
+       } else
+               mutex_unlock(&isp_dev->power_lock);
 
        return ret;
 }
@@ -943,6 +963,12 @@ int stf_isp_register(struct stf_isp_dev *isp_dev,
 
        pads[STF_ISP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
        pads[STF_ISP_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
+       pads[STF_ISP_PAD_SRC_SS0].flags = MEDIA_PAD_FL_SOURCE;
+       pads[STF_ISP_PAD_SRC_SS1].flags = MEDIA_PAD_FL_SOURCE;
+       pads[STF_ISP_PAD_SRC_ITIW].flags = MEDIA_PAD_FL_SOURCE;
+       pads[STF_ISP_PAD_SRC_ITIR].flags = MEDIA_PAD_FL_SOURCE;
+       pads[STF_ISP_PAD_SRC_RAW].flags = MEDIA_PAD_FL_SOURCE;
+       pads[STF_ISP_PAD_SRC_SCD_Y].flags = MEDIA_PAD_FL_SOURCE;
 
        sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
        sd->entity.ops = &isp_media_ops;
@@ -982,6 +1008,7 @@ int stf_isp_unregister(struct stf_isp_dev *isp_dev)
        media_entity_cleanup(&isp_dev->subdev.entity);
        v4l2_ctrl_handler_free(&isp_dev->ctrls.handler);
        mutex_destroy(&isp_dev->stream_lock);
+       mutex_destroy(&isp_dev->power_lock);
        mutex_destroy(&isp_dev->setfile_lock);
        return 0;
 }
index 926e79d..97c3b2c 100644 (file)
 #define STF_ISP_NAME "stf_isp"
 
 //#define ISP_USE_CSI_AND_SC_DONE_INTERRUPT  1
-#define STF_ISP_PAD_SINK     0
-#define STF_ISP_PAD_SRC      1
-#define STF_ISP_PADS_NUM     2
+
+#define STF_ISP_PAD_SINK         0
+#define STF_ISP_PAD_SRC          1
+#define STF_ISP_PAD_SRC_SS0      2
+#define STF_ISP_PAD_SRC_SS1      3
+#define STF_ISP_PAD_SRC_ITIW     4
+#define STF_ISP_PAD_SRC_ITIR     5
+#define STF_ISP_PAD_SRC_RAW      6
+#define STF_ISP_PAD_SRC_SCD_Y    7
+#define STF_ISP_PADS_NUM         8
 
 #define STF_ISP0_SETFILE     "stf_isp0_fw.bin"
 #define STF_ISP1_SETFILE     "stf_isp1_fw.bin"
 
-#define SCALER_RATIO_MAX     1  // no compose function
+#define ISP_SCD_BUFFER_SIZE     (19 * 256 * 4)  // align 128
+#define ISP_YHIST_BUFFER_SIZE   (64 * 4)
+#define ISP_SCD_Y_BUFFER_SIZE   (ISP_SCD_BUFFER_SIZE + ISP_YHIST_BUFFER_SIZE)
+#define ISP_RAW_DATA_BITS       12
+#define SCALER_RATIO_MAX        1  // no compose function
 #define STF_ISP_REG_OFFSET_MAX  0x0FFF
 #define STF_ISP_REG_DELAY_MAX   100
 
 #define ISP_REG_CSIINTS_ADDR    0x00000008
+#define ISP_REG_SENSOR          0x00000014
 #define ISP_REG_DUMP_CFG_0      0x00000024
 #define ISP_REG_DUMP_CFG_1      0x00000028
+#define ISP_REG_SCD_CFG_0       0x00000098
+#define ISP_REG_SCD_CFG_1       0x0000009C
+#define ISP_REG_SC_CFG_1        0x000000BC
 #define ISP_REG_IESHD_ADDR      0x00000A50
+#define ISP_REG_SS0AY           0x00000A94
+#define ISP_REG_SS0AUV          0x00000A98
+#define ISP_REG_SS0S            0x00000A9C
+#define ISP_REG_SS0IW           0x00000AA8
+#define ISP_REG_SS1AY           0x00000AAC
+#define ISP_REG_SS1AUV          0x00000AB0
+#define ISP_REG_SS1S            0x00000AB4
+#define ISP_REG_SS1IW           0x00000AC0
+#define ISP_REG_YHIST_CFG_4     0x00000CD8
+#define ISP_REG_ITIIWSR         0x00000B20
+#define ISP_REG_ITIDWLSR        0x00000B24
+#define ISP_REG_ITIDWYSAR       0x00000B28
+#define ISP_REG_ITIDWUSAR       0x00000B2C
+#define ISP_REG_ITIDRYSAR       0x00000B30
+#define ISP_REG_ITIDRUSAR       0x00000B34
+#define ISP_REG_ITIPDFR         0x00000B38
+#define ISP_REG_ITIDRLSR        0x00000B3C
+#define ISP_REG_ITIBSR          0x00000B40
+#define ISP_REG_ITIAIR          0x00000B44
+#define ISP_REG_ITIDPSR         0x00000B48
 
 enum {
        EN_INT_NONE                 = 0,
@@ -39,6 +74,21 @@ enum {
        EN_INT_ALL                  = (0xF << 24),
 };
 
+enum {
+       DVP_SENSOR = 0,
+       CSI_SENSOR,
+};
+
+#define ISP_AWB_OECF_SKIP_FRAME  1
+// 0x0BC [31:30] SEL - sc0 input mux for sc awb
+// 00 : after DEC, 01 : after OBC, 10 : after OECF, 11 : after AWB
+enum scd_type {
+       DEC_TYPE = 0,
+       OBC_TYPE,
+       OECF_TYPE,
+       AWB_TYPE
+};
+
 struct isp_format {
        u32 code;
        u8 bpp;
@@ -119,6 +169,8 @@ struct stf_isp_dev {
        const struct isp_format *formats;
        unsigned int nformats;
        struct isp_hw_ops *hw_ops;
+       struct mutex power_lock;
+       int power_count;
        struct mutex stream_lock;
        int stream_count;
        atomic_t shadow_count;
old mode 100755 (executable)
new mode 100644 (file)
index 62cf9e6..a165033
@@ -51,6 +51,38 @@ static const struct stfcamss_format_info formats_pix_st7110_isp[] = {
          { { 1, 1 } }, { { 2, 3 } }, { 8 } },
 };
 
+static const struct stfcamss_format_info formats_st7110_isp_iti[] = {
+       //  raw format
+       { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10, 1,
+         { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+       { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10, 1,
+         { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+       { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10, 1,
+         { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+       { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10, 1,
+         { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+       { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12, 1,
+         { { 1, 1 } }, { { 1, 1 } }, { 12 } },
+       { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12, 1,
+         { { 1, 1 } }, { { 1, 1 } }, { 12 } },
+       { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12, 1,
+         { { 1, 1 } }, { { 1, 1 } }, { 12 } },
+       { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12, 1,
+         { { 1, 1 } }, { { 1, 1 } }, { 12 } },
+
+       // YUV420
+       { MEDIA_BUS_FMT_Y12_1X12, V4L2_PIX_FMT_NV12, 1,
+         { { 1, 1 } }, { { 2, 3 } }, { 8 } },
+       { MEDIA_BUS_FMT_Y12_1X12, V4L2_PIX_FMT_NV21, 1,
+         { { 1, 1 } }, { { 2, 3 } }, { 8 } },
+
+       // YUV444
+       { MEDIA_BUS_FMT_YUV8_1X24, V4L2_PIX_FMT_NV24, 1,
+         { { 1, 1 } }, { { 1, 3 } }, { 8 } },
+       { MEDIA_BUS_FMT_VUY8_1X24, V4L2_PIX_FMT_NV42, 1,
+         { { 1, 1 } }, { { 1, 3 } }, { 8 } },
+};
+
 static int video_find_format(u32 code, u32 pixelformat,
                                const struct stfcamss_format_info *formats,
                                unsigned int nformats)
@@ -258,6 +290,11 @@ static int video_queue_setup(struct vb2_queue *q,
                if (!sizes[0])
                        st_err(ST_VIDEO, "%s: error size is zero!!!\n", __func__);
        }
+       if ((video->id == VIN_LINE_ISP0_SCD_Y
+               || video->id == VIN_LINE_ISP1_SCD_Y)
+               && sizes[0] < ISP_SCD_Y_BUFFER_SIZE) {
+               sizes[0] = ISP_SCD_Y_BUFFER_SIZE;
+       }
 
        st_info(ST_VIDEO, "%s, planes = %d, size = %d\n",
                        __func__, *num_planes, sizes[0]);
@@ -289,7 +326,7 @@ static int video_buf_init(struct vb2_buffer *vb)
                        || fmt_mp->pixelformat == V4L2_PIX_FMT_NV16
                        || fmt_mp->pixelformat == V4L2_PIX_FMT_NV61))
                        buffer->addr[1] = buffer->addr[0] +
-                                       fmt_mp->width *
+                                       fmt_mp->plane_fmt[0].bytesperline *
                                        fmt_mp->height;
        } else {
                paddr = vb2_plane_cookie(vb, 0);
@@ -299,10 +336,14 @@ static int video_buf_init(struct vb2_buffer *vb)
                        || fmt->pixelformat == V4L2_PIX_FMT_NV16
                        || fmt->pixelformat == V4L2_PIX_FMT_NV61)
                        buffer->addr[1] = buffer->addr[0] +
-                               fmt->width *
+                               fmt->bytesperline *
                                fmt->height;
        }
 
+       if (video->id == VIN_LINE_ISP0_SCD_Y
+               || video->id == VIN_LINE_ISP1_SCD_Y)
+               buffer->addr[1] = buffer->addr[0] + ISP_YHIST_BUFFER_SIZE;
+
        return 0;
 }
 
@@ -325,8 +366,11 @@ static int video_buf_prepare(struct vb2_buffer *vb)
                                        fmt_mp->plane_fmt[i].sizeimage);
                }
        } else {
-               if (fmt->sizeimage > vb2_plane_size(vb, 0))
+               if (fmt->sizeimage > vb2_plane_size(vb, 0)) {
+                       st_err(ST_VIDEO, "sizeimage = %d, plane size = %d\n",
+                               fmt->sizeimage, (unsigned int)vb2_plane_size(vb, 0));
                        return -EINVAL;
+               }
                vb2_set_plane_payload(vb, 0, fmt->sizeimage);
        }
 
@@ -507,7 +551,8 @@ static int video_start_streaming(struct vb2_queue *q, unsigned int count)
        int ret;
 
 #ifdef USE_MEDIA_PIPELINE
-       ret = media_pipeline_start(&vdev->entity, &video->pipe);
+       // ret = media_pipeline_start(&vdev->entity, &video->pipe);
+       ret = media_pipeline_start(&vdev->entity, &video->stfcamss->pipe);
        if (ret < 0) {
                st_err(ST_VIDEO,
                        "Failed to media_pipeline_start: %d\n", ret);
@@ -1188,7 +1233,7 @@ int video_g_ctrl(struct file *file, void *fh,
        struct v4l2_subdev *subdev;
        int ret;
 
-       subdev = get_senname(file, __func__);
+       subdev = get_senname(file, (char *)__func__);
        if (!subdev)
                return -EINVAL;
 
@@ -1204,7 +1249,7 @@ static int video_s_ctrl(struct file *file, void *fh,
        struct v4l2_fh *vfh;
        int ret;
 
-       subdev = get_senname(file, __func__);
+       subdev = get_senname(file, (char *)__func__);
        if (!subdev)
                return -EINVAL;
 
@@ -1224,7 +1269,7 @@ static int video_query_ext_ctrl(struct file *file, void *fh,
        struct v4l2_subdev *subdev;
        int ret;
 
-       subdev = get_senname(file, __func__);
+       subdev = get_senname(file, (char *)__func__);
        if (!subdev)
                return -EINVAL;
 
@@ -1242,7 +1287,7 @@ static int video_g_ext_ctrls(struct file *file, void *fh,
        struct v4l2_subdev *subdev;
        int ret;
 
-       subdev = get_senname(file, __func__);
+       subdev = get_senname(file, (char *)__func__);
        if (!subdev)
                return -EINVAL;
 
@@ -1283,7 +1328,7 @@ static int video_s_ext_ctrls(struct file *file, void *fh,
        struct v4l2_fh *vfh;
        int ret;
 
-       subdev = get_senname(file, __func__);
+       subdev = get_senname(file, (char *)__func__);
        if (!subdev)
                return -EINVAL;
 
@@ -1305,7 +1350,7 @@ static int video_try_ext_ctrls(struct file *file, void *fh,
        struct v4l2_fh *vfh;
        int ret;
 
-       subdev = get_senname(file, __func__);
+       subdev = get_senname(file, (char *)__func__);
        if (!subdev)
                return -EINVAL;
 
@@ -1318,6 +1363,7 @@ static int video_try_ext_ctrls(struct file *file, void *fh,
        return ret;
 }
 
+
 #ifdef UNUSED_CODE
 static int video_querymenu(struct file *file, void *fh,
                               struct v4l2_querymenu *qm)
@@ -1325,9 +1371,10 @@ static int video_querymenu(struct file *file, void *fh,
        struct v4l2_subdev *subdev;
        int ret;
 
-       subdev = get_senname(file, __func__);
+       subdev = get_senname(file, (char *)__func__);
        if (!subdev)
                return -EINVAL;
+
        ret = v4l2_querymenu(subdev->ctrl_handler, qm);
 
        return ret;
@@ -1364,9 +1411,6 @@ static const struct v4l2_ioctl_ops stf_vid_ioctl_ops = {
        .vidioc_queryctrl               = video_queryctrl,
        .vidioc_s_ext_ctrls             = video_s_ext_ctrls,
        .vidioc_try_ext_ctrls           = video_try_ext_ctrls,
-       //.vidioc_query_ext_ctrl          = video_query_ext_ctrl,
-       //.vidioc_querymenu               = video_querymenu,
-
 };
 
 static const struct v4l2_ioctl_ops stf_vid_ioctl_ops_mp = {
@@ -1399,8 +1443,25 @@ static const struct v4l2_ioctl_ops stf_vid_ioctl_ops_mp = {
        .vidioc_queryctrl               = video_queryctrl,
        .vidioc_s_ext_ctrls             = video_s_ext_ctrls,
        .vidioc_try_ext_ctrls           = video_try_ext_ctrls,
-//     .vidioc_querymenu               = video_querymenu,
-//     .vidioc_query_ext_ctrl          = video_query_ext_ctrl,
+};
+
+static const struct v4l2_ioctl_ops stf_vid_ioctl_ops_out = {
+       .vidioc_querycap                = video_querycap,
+       .vidioc_enum_fmt_vid_out        = video_enum_fmt,
+       .vidioc_enum_framesizes         = video_enum_framesizes,
+       .vidioc_enum_frameintervals     = video_enum_frameintervals,
+       .vidioc_g_fmt_vid_out           = video_g_fmt,
+       .vidioc_s_fmt_vid_out           = video_s_fmt,
+       .vidioc_try_fmt_vid_out         = video_try_fmt,
+       .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
+       .vidioc_querybuf                = vb2_ioctl_querybuf,
+       .vidioc_qbuf                    = vb2_ioctl_qbuf,
+       .vidioc_expbuf                  = vb2_ioctl_expbuf,
+       .vidioc_dqbuf                   = vb2_ioctl_dqbuf,
+       .vidioc_create_bufs             = vb2_ioctl_create_bufs,
+       .vidioc_prepare_buf             = vb2_ioctl_prepare_buf,
+       .vidioc_streamon                = vb2_ioctl_streamon,
+       .vidioc_streamoff               = vb2_ioctl_streamoff,
 };
 
 static int video_open(struct file *file)
@@ -1553,13 +1614,15 @@ int stf_video_register(struct stfcamss_video *video,
        q->drv_priv = video;
        q->mem_ops = &vb2_dma_contig_memops;
        q->ops = &stf_video_vb2_q_ops;
-       q->type = is_mp ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
-               V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       //q->type = is_mp ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+       //      V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       q->type = video->type;
        q->io_modes = VB2_DMABUF | VB2_MMAP | VB2_READ;
        q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
        q->buf_struct_size = sizeof(struct stfcamss_buffer);
        q->dev = video->stfcamss->dev;
        q->lock = &video->q_lock;
+       q->min_buffers_needed = STFCAMSS_MIN_BUFFERS;
        ret = vb2_queue_init(q);
        if (ret < 0) {
                st_err(ST_VIDEO,
@@ -1581,16 +1644,27 @@ int stf_video_register(struct stfcamss_video *video,
        if (video->id == VIN_LINE_WR) {
                video->formats = formats_pix_st7110_wr;
                video->nformats = ARRAY_SIZE(formats_pix_st7110_wr);
-               video->bpl_alignment = 8;
+               video->bpl_alignment = STFCAMSS_FRAME_WIDTH_ALIGN_8;
        } else if (video->id == VIN_LINE_ISP0
-               || video->id == VIN_LINE_ISP1) {  // ISP0/ISP1
+               || video->id == VIN_LINE_ISP1
+               || video->id == VIN_LINE_ISP0_SS0
+               || video->id == VIN_LINE_ISP1_SS0
+               || video->id == VIN_LINE_ISP0_SS1
+               || video->id == VIN_LINE_ISP1_SS1) {  // ISP0/ISP1
                video->formats = formats_pix_st7110_isp;
                video->nformats = ARRAY_SIZE(formats_pix_st7110_isp);
-               video->bpl_alignment = 8;
-       } else {
+               video->bpl_alignment = STFCAMSS_FRAME_WIDTH_ALIGN_8;
+       } else if (video->id == VIN_LINE_ISP0_ITIW
+               || video->id == VIN_LINE_ISP0_ITIR
+               || video->id == VIN_LINE_ISP1_ITIW
+               || video->id == VIN_LINE_ISP1_ITIR) {  // ISP0/ISP1
+               video->formats = formats_st7110_isp_iti;
+               video->nformats = ARRAY_SIZE(formats_st7110_isp_iti);
+               video->bpl_alignment = STFCAMSS_FRAME_WIDTH_ALIGN_8;
+       } else { // raw/scdump/yhist
                video->formats = formats_raw_st7110_isp;
                video->nformats = ARRAY_SIZE(formats_raw_st7110_isp);
-               video->bpl_alignment = 16 * 8;
+               video->bpl_alignment = STFCAMSS_FRAME_WIDTH_ALIGN_128;
        }
        video->is_mp = is_mp;
 
@@ -1601,13 +1675,22 @@ int stf_video_register(struct stfcamss_video *video,
        }
 
        vdev->fops = &stf_vid_fops;
-       vdev->device_caps = is_mp ? V4L2_CAP_VIDEO_CAPTURE_MPLANE :
+       if (video->id == VIN_LINE_ISP0_ITIR
+               || video->id == VIN_LINE_ISP1_ITIR) {
+               vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT;
+               vdev->vfl_dir = VFL_DIR_TX;
+       } else {
+               vdev->device_caps = is_mp ? V4L2_CAP_VIDEO_CAPTURE_MPLANE :
                        V4L2_CAP_VIDEO_CAPTURE;
+               vdev->vfl_dir = VFL_DIR_RX;
+       }
        vdev->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
-       vdev->ioctl_ops = is_mp ? &stf_vid_ioctl_ops_mp : &stf_vid_ioctl_ops;
+       if (video->type == V4L2_CAP_VIDEO_OUTPUT)
+               vdev->ioctl_ops = &stf_vid_ioctl_ops_out;
+       else
+               vdev->ioctl_ops = is_mp ? &stf_vid_ioctl_ops_mp : &stf_vid_ioctl_ops;
        vdev->release = stf_video_release;
        vdev->v4l2_dev = v4l2_dev;
-       vdev->vfl_dir = VFL_DIR_RX;
        vdev->queue = &video->vb2_q;
        vdev->lock = &video->lock;
        //strlcpy(vdev->name, name, sizeof(vdev->name));
index f8a21ba..896124a 100755 (executable)
 #include <media/v4l2-fh.h>
 #include <media/v4l2-ioctl.h>
 
-#define STFCAMSS_FRAME_MIN_WIDTH           1
+#define STFCAMSS_FRAME_MIN_WIDTH           64
 #define STFCAMSS_FRAME_MAX_WIDTH           8191
-#define STFCAMSS_FRAME_MIN_HEIGHT          1
+#define STFCAMSS_FRAME_MIN_HEIGHT          64
 #define STFCAMSS_FRAME_MAX_HEIGHT_RDI      8191
 #define STFCAMSS_FRAME_MAX_HEIGHT_PIX      4096
-#define STFCAMSS_FRAME_WIDTH_ALIGN         8
+#define STFCAMSS_FRAME_WIDTH_ALIGN_8       8
+#define STFCAMSS_FRAME_WIDTH_ALIGN_128     128
+#define STFCAMSS_MIN_BUFFERS               2
 
 struct stfcamss_buffer {
        struct vb2_v4l2_buffer vb;
index 9a46913..79d4a34 100644 (file)
@@ -9,12 +9,10 @@
 
 #include "stfcamss.h"
 
-#define STF_VIN_NAME "stf_vin"
-
-#define vin_line_array(ptr_line)               \
+#define vin_line_array(ptr_line) \
                ((const struct vin_line (*)[]) &(ptr_line[-(ptr_line->id)]))
 
-#define line_to_vin2_dev(ptr_line)             \
+#define line_to_vin2_dev(ptr_line) \
                container_of(vin_line_array(ptr_line), struct stf_vin2_dev, line)
 
 #define VIN_FRAME_DROP_MAX_VAL 30
@@ -51,12 +49,42 @@ static char *get_line_subdevname(int line_id)
        case VIN_LINE_ISP1:
                name = "isp1";
                break;
+       case VIN_LINE_ISP0_SS0:
+               name = "isp0_ss0";
+               break;
+       case VIN_LINE_ISP1_SS0:
+               name = "isp1_ss0";
+               break;
+       case VIN_LINE_ISP0_SS1:
+               name = "isp0_ss1";
+               break;
+       case VIN_LINE_ISP1_SS1:
+               name = "isp1_ss1";
+               break;
+       case VIN_LINE_ISP0_ITIW:
+               name = "isp0_itiw";
+               break;
+       case VIN_LINE_ISP1_ITIW:
+               name = "isp1_itiw";
+               break;
+       case VIN_LINE_ISP0_ITIR:
+               name = "isp0_itir";
+               break;
+       case VIN_LINE_ISP1_ITIR:
+               name = "isp1_itir";
+               break;
        case VIN_LINE_ISP0_RAW:
                name = "isp0_raw";
                break;
        case VIN_LINE_ISP1_RAW:
                name = "isp1_raw";
                break;
+       case VIN_LINE_ISP0_SCD_Y:
+               name = "isp0_scd_y";
+               break;
+       case VIN_LINE_ISP1_SCD_Y:
+               name = "isp1_scd_y";
+               break;
        default:
                name = "unknow";
                break;
@@ -186,7 +214,10 @@ int stf_vin_subdev_init(struct stfcamss *stfcamss)
 
                is_mp = i == VIN_LINE_WR ? false : true;
                is_mp = false;
-               l->video_out.type = is_mp ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+               if (i == VIN_LINE_ISP0_ITIR || i == VIN_LINE_ISP1_ITIR)
+                       l->video_out.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+               else
+                       l->video_out.type = is_mp ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
                                V4L2_BUF_TYPE_VIDEO_CAPTURE;
                l->video_out.stfcamss = stfcamss;
                l->id = i;
@@ -258,23 +289,8 @@ static int vin_enable_output(struct vin_line *line)
 {
        struct vin_output *output = &line->output;
        unsigned long flags;
-       unsigned int frame_skip = 0;
-       struct media_entity *sensor;
-
-       sensor = stfcamss_find_sensor(&line->subdev.entity);
-       if (sensor) {
-               struct v4l2_subdev *subdev =
-                                       media_entity_to_v4l2_subdev(sensor);
-
-               v4l2_subdev_call(subdev, sensor, g_skip_frames, &frame_skip);
-               frame_skip += VIN_FRAME_DROP_MIN_VAL;
-               if (frame_skip > VIN_FRAME_DROP_MAX_VAL)
-                       frame_skip = VIN_FRAME_DROP_MAX_VAL;
-               st_debug(ST_VIN, "%s, frame_skip %d\n", __func__, frame_skip);
-       }
 
        spin_lock_irqsave(&line->output_lock, flags);
-       output->frame_skip = frame_skip;
 
        output->state = VIN_OUTPUT_IDLE;
 
@@ -479,8 +495,16 @@ static int vin_set_format(struct v4l2_subdev *sd,
        if (format == NULL)
                return -EINVAL;
 
-       vin_try_format(line, state, fmt->pad, &fmt->format, fmt->which);
-       *format = fmt->format;
+       mutex_lock(&line->stream_lock);
+       if (line->stream_count) {
+               fmt->format = *format;
+               mutex_unlock(&line->stream_lock);
+               goto out;
+       } else {
+               vin_try_format(line, state, fmt->pad, &fmt->format, fmt->which);
+               *format = fmt->format;
+       }
+       mutex_unlock(&line->stream_lock);
 
        if (fmt->pad == STF_VIN_PAD_SINK) {
                /* Propagate the format from sink to source */
@@ -492,6 +516,7 @@ static int vin_set_format(struct v4l2_subdev *sd,
                                        fmt->which);
        }
 
+out:
        return 0;
 }
 
@@ -526,9 +551,8 @@ static void vin_output_init_addrs(struct vin_line *line)
                ping_addr = output->buf[0]->addr[0];
                y_addr = output->buf[0]->addr[0];
                uv_addr = output->buf[0]->addr[1];
-
        } else
-               ping_addr = 0;
+               return;
 
        if (output->buf[1])
                pong_addr = output->buf[1]->addr[0];
@@ -552,11 +576,42 @@ static void vin_output_init_addrs(struct vin_line *line)
                        y_addr, uv_addr);
 
                break;
+       case VIN_LINE_ISP0_SS0: // isp0_ss0
+       case VIN_LINE_ISP1_SS0: // isp1_ss0
+               vin_dev->hw_ops->vin_isp_set_ss0_addr(vin_dev,
+                       line->id - VIN_LINE_ISP0_SS0,
+                       y_addr, uv_addr);
+               break;
+       case VIN_LINE_ISP0_SS1: // isp0_ss1
+       case VIN_LINE_ISP1_SS1: // isp1_ss1
+               vin_dev->hw_ops->vin_isp_set_ss1_addr(vin_dev,
+                       line->id - VIN_LINE_ISP0_SS1,
+                       y_addr, uv_addr);
+               break;
+       case VIN_LINE_ISP0_ITIW: // isp0_itiw
+       case VIN_LINE_ISP1_ITIW: // isp1_itiw
+               vin_dev->hw_ops->vin_isp_set_itiw_addr(vin_dev,
+                       line->id - VIN_LINE_ISP0_ITIW,
+                       y_addr, uv_addr);
+               break;
+       case VIN_LINE_ISP0_ITIR: // isp0_itir
+       case VIN_LINE_ISP1_ITIR: // isp1_itir
+               vin_dev->hw_ops->vin_isp_set_itir_addr(vin_dev,
+                       line->id - VIN_LINE_ISP0_ITIR,
+                       y_addr, uv_addr);
+               break;
        case VIN_LINE_ISP0_RAW: // isp0_raw
        case VIN_LINE_ISP1_RAW: // isp1_raw
                vin_dev->hw_ops->vin_isp_set_raw_addr(vin_dev,
                        line->id - VIN_LINE_ISP0_RAW, y_addr);
                break;
+       case VIN_LINE_ISP0_SCD_Y: // isp0_scd_y
+       case VIN_LINE_ISP1_SCD_Y: // isp1_scd_y
+               output->frame_skip = ISP_AWB_OECF_SKIP_FRAME;
+               vin_dev->hw_ops->vin_isp_set_scd_addr(vin_dev,
+                       line->id - VIN_LINE_ISP0_SCD_Y, y_addr, uv_addr,
+                       AWB_TYPE);
+               break;
        default:
                break;
        }
@@ -700,6 +755,11 @@ static void vin_buf_update_on_new(struct vin_line *line,
                                struct vin_output *output,
                                struct stfcamss_buffer *new_buf)
 {
+#ifdef VIN_TWO_BUFFER
+       struct stf_vin2_dev *vin_dev = line_to_vin2_dev(line);
+       int inactive_idx;
+#endif
+
        switch (output->state) {
        case VIN_OUTPUT_SINGLE:
 #ifdef VIN_TWO_BUFFER
@@ -798,6 +858,7 @@ static void vin_change_buffer(struct vin_line *line)
        dma_addr_t *new_addr;
        unsigned long flags;
        u32 active_index;
+       int scd_type;
 
        if (output->state == VIN_OUTPUT_OFF
                || output->state == VIN_OUTPUT_STOPPING
@@ -857,22 +918,65 @@ static void vin_change_buffer(struct vin_line *line)
                vin_dev->hw_ops->vin_wr_set_pong_addr(vin_dev,
                                new_addr[0]);
 #endif
-               break;
-       case VIN_LINE_ISP0: // isp0
-       case VIN_LINE_ISP1: // isp1
-               vin_dev->hw_ops->vin_isp_set_yuv_addr(vin_dev,
-                       line->id - VIN_LINE_ISP0,
-                       new_addr[0], new_addr[1]);
-               break;
-       case VIN_LINE_ISP0_RAW: // isp0_raw
-       case VIN_LINE_ISP1_RAW: // isp1_raw
-               vin_dev->hw_ops->vin_isp_set_raw_addr(vin_dev,
-                       line->id - VIN_LINE_ISP0_RAW, new_addr[0]);
-               break;
-
-       default:
-               break;
-       }
+                       break;
+               case VIN_LINE_ISP0: // isp0
+               case VIN_LINE_ISP1: // isp1
+                       vin_dev->hw_ops->vin_isp_set_yuv_addr(vin_dev,
+                               line->id - VIN_LINE_ISP0,
+                               new_addr[0], new_addr[1]);
+                       break;
+               case VIN_LINE_ISP0_SS0: // isp0_ss0
+               case VIN_LINE_ISP1_SS0: // isp1_ss0
+                       vin_dev->hw_ops->vin_isp_set_ss0_addr(vin_dev,
+                               line->id - VIN_LINE_ISP0_SS0,
+                               new_addr[0], new_addr[1]);
+                       break;
+               case VIN_LINE_ISP0_SS1: // isp0_ss1
+               case VIN_LINE_ISP1_SS1: // isp1_ss1
+                       vin_dev->hw_ops->vin_isp_set_ss1_addr(vin_dev,
+                               line->id - VIN_LINE_ISP0_SS1,
+                               new_addr[0], new_addr[1]);
+                       break;
+               case VIN_LINE_ISP0_ITIW: // isp0_itiw
+               case VIN_LINE_ISP1_ITIW: // isp1_itiw
+                       vin_dev->hw_ops->vin_isp_set_itiw_addr(vin_dev,
+                               line->id - VIN_LINE_ISP0_ITIW,
+                               new_addr[0], new_addr[1]);
+                       break;
+               case VIN_LINE_ISP0_ITIR: // isp0_itir
+               case VIN_LINE_ISP1_ITIR: // isp1_itir
+                       vin_dev->hw_ops->vin_isp_set_itir_addr(vin_dev,
+                               line->id - VIN_LINE_ISP0_ITIR,
+                               new_addr[0], new_addr[1]);
+                       break;
+               case VIN_LINE_ISP0_RAW: // isp0_raw
+               case VIN_LINE_ISP1_RAW: // isp1_raw
+                       vin_dev->hw_ops->vin_isp_set_raw_addr(vin_dev,
+                               line->id - VIN_LINE_ISP0_RAW, new_addr[0]);
+                       break;
+               case VIN_LINE_ISP0_SCD_Y: // isp0_scd_y
+               case VIN_LINE_ISP1_SCD_Y: // isp1_scd_y
+                       scd_type = vin_dev->hw_ops->vin_isp_get_scd_type(vin_dev,
+                                       line->id - VIN_LINE_ISP0_SCD_Y);
+                       ready_buf->vb.flags &= ~(V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME);
+                       if (scd_type == AWB_TYPE)
+                               ready_buf->vb.flags |= V4L2_BUF_FLAG_PFRAME;
+                       else
+                               ready_buf->vb.flags |= V4L2_BUF_FLAG_BFRAME;
+                       if (!output->frame_skip) {
+                               output->frame_skip = ISP_AWB_OECF_SKIP_FRAME;
+                               scd_type = scd_type == AWB_TYPE ? OECF_TYPE : AWB_TYPE;
+                       } else {
+                               output->frame_skip--;
+                               scd_type = scd_type == AWB_TYPE ? AWB_TYPE : OECF_TYPE;
+                       }
+                       vin_dev->hw_ops->vin_isp_set_scd_addr(vin_dev,
+                               line->id - VIN_LINE_ISP0_SCD_Y, new_addr[0], new_addr[1],
+                               scd_type);
+                       break;
+               default:
+                       break;
+               }
 
                vin_buf_add_ready(output, ready_buf);
        }
index 584d1e6..92a57b6 100755 (executable)
@@ -13,6 +13,8 @@
 
 #include "stf_video.h"
 
+#define STF_VIN_NAME "stf_vin"
+
 #define STF_VIN_PAD_SINK   0
 #define STF_VIN_PAD_SRC    1
 #define STF_VIN_PADS_NUM   2
@@ -47,9 +49,19 @@ enum vin_line_id {
        VIN_LINE_WR = 0,
        VIN_LINE_ISP0 = 1,
        VIN_LINE_ISP1 = 2,
-       VIN_LINE_ISP0_RAW = 3,
-       VIN_LINE_ISP1_RAW = 4,
-       VIN_LINE_MAX = 5
+       VIN_LINE_ISP0_SS0 = 3,
+       VIN_LINE_ISP1_SS0 = 4,
+       VIN_LINE_ISP0_SS1 = 5,
+       VIN_LINE_ISP1_SS1 = 6,
+       VIN_LINE_ISP0_ITIW = 7,
+       VIN_LINE_ISP1_ITIW = 8,
+       VIN_LINE_ISP0_ITIR = 9,
+       VIN_LINE_ISP1_ITIR = 10,
+       VIN_LINE_ISP0_RAW = 11,
+       VIN_LINE_ISP1_RAW = 12,
+       VIN_LINE_ISP0_SCD_Y = 13,
+       VIN_LINE_ISP1_SCD_Y = 14,
+       VIN_LINE_MAX = 15
 };
 
 enum subdev_type;
@@ -94,6 +106,22 @@ struct vin_hw_ops {
                        dma_addr_t y_addr, dma_addr_t uv_addr);
        void (*vin_isp_set_raw_addr)(struct stf_vin2_dev *vin_dev,
                        int isp_id, dma_addr_t raw_addr);
+       void (*vin_isp_set_ss0_addr)(struct stf_vin2_dev *vin_dev,
+                       int isp_id,
+                       dma_addr_t y_addr, dma_addr_t uv_addr);
+       void (*vin_isp_set_ss1_addr)(struct stf_vin2_dev *vin_dev,
+                       int isp_id,
+                       dma_addr_t y_addr, dma_addr_t uv_addr);
+       void (*vin_isp_set_itiw_addr)(struct stf_vin2_dev *vin_dev,
+                       int isp_id,
+                       dma_addr_t y_addr, dma_addr_t uv_addr);
+       void (*vin_isp_set_itir_addr)(struct stf_vin2_dev *vin_dev,
+                       int isp_id,
+                       dma_addr_t y_addr, dma_addr_t uv_addr);
+       void (*vin_isp_set_scd_addr)(struct stf_vin2_dev *vin_dev,
+                       int isp_id, dma_addr_t yhist_addr,
+                       dma_addr_t scd_addr, int scd_type);
+       int (*vin_isp_get_scd_type)(struct stf_vin2_dev *vin_dev, int isp_id);
        irqreturn_t (*vin_wr_irq_handler)(int irq, void *priv);
        irqreturn_t (*vin_isp_irq_handler)(int irq, void *priv);
        irqreturn_t (*vin_isp_csi_irq_handler)(int irq, void *priv);
index 3766589..c32486f 100644 (file)
@@ -39,7 +39,7 @@ static irqreturn_t stf_vin_isp_irq_handler(int irq, void *priv)
        struct stf_vin2_dev *vin_dev = priv;
        struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
        void __iomem *ispbase;
-       u32 int_status;
+       u32 int_status, value;
        int isp_id = irq == vin->isp0_irq ? 0 : 1;
 
        if (isp_id == 0)
@@ -50,15 +50,35 @@ static irqreturn_t stf_vin_isp_irq_handler(int irq, void *priv)
        int_status = reg_read(ispbase, ISP_REG_ISP_CTRL_0);
 
        if (int_status & BIT(24)) {
+               if ((int_status & BIT(11)))
+                       vin_dev->hw_ops->isr_buffer_done(
+                               &vin_dev->line[VIN_LINE_ISP0_SS0 + isp_id], &params);
+
+               if ((int_status & BIT(12)))
+                       vin_dev->hw_ops->isr_buffer_done(
+                               &vin_dev->line[VIN_LINE_ISP0_SS1 + isp_id], &params);
+
                if ((int_status & BIT(20)))
                        vin_dev->hw_ops->isr_buffer_done(
                                &vin_dev->line[VIN_LINE_ISP0 + isp_id], &params);
 
+               value = reg_read(ispbase, ISP_REG_ITIDPSR);
+               if ((value & BIT(17)))
+                       vin_dev->hw_ops->isr_buffer_done(
+                               &vin_dev->line[VIN_LINE_ISP0_ITIW + isp_id], &params);
+               if ((value & BIT(16)))
+                       vin_dev->hw_ops->isr_buffer_done(
+                               &vin_dev->line[VIN_LINE_ISP0_ITIR + isp_id], &params);
+
 #ifndef ISP_USE_CSI_AND_SC_DONE_INTERRUPT
                if (int_status & BIT(25))
                        vin_dev->hw_ops->isr_buffer_done(
                                &vin_dev->line[VIN_LINE_ISP0_RAW + isp_id], &params);
 
+               if (int_status & BIT(26))
+                       vin_dev->hw_ops->isr_buffer_done(
+                               &vin_dev->line[VIN_LINE_ISP0_SCD_Y + isp_id], &params);
+
                /* clear interrupt */
                reg_write(ispbase, ISP_REG_ISP_CTRL_0, (int_status & ~EN_INT_ALL)
                                | EN_INT_ISP_DONE | EN_INT_CSI_DONE | EN_INT_SC_DONE);
@@ -75,6 +95,7 @@ static irqreturn_t stf_vin_isp_irq_handler(int irq, void *priv)
 
 static irqreturn_t stf_vin_isp_csi_irq_handler(int irq, void *priv)
 {
+       static struct vin_params params;
        struct stf_vin2_dev *vin_dev = priv;
        struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
        void __iomem *ispbase;
@@ -89,6 +110,9 @@ static irqreturn_t stf_vin_isp_csi_irq_handler(int irq, void *priv)
        int_status = reg_read(ispbase, ISP_REG_ISP_CTRL_0);
 
        if (int_status & BIT(25)) {
+               vin_dev->hw_ops->isr_buffer_done(
+                       &vin_dev->line[VIN_LINE_ISP0_RAW + isp_id], &params);
+
                /* clear interrupt */
                reg_write(ispbase, ISP_REG_ISP_CTRL_0,
                        (int_status & ~EN_INT_ALL) | EN_INT_CSI_DONE);
@@ -100,6 +124,7 @@ static irqreturn_t stf_vin_isp_csi_irq_handler(int irq, void *priv)
 
 static irqreturn_t stf_vin_isp_scd_irq_handler(int irq, void *priv)
 {
+       static struct vin_params params;
        struct stf_vin2_dev *vin_dev = priv;
        struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
        void __iomem *ispbase;
@@ -114,6 +139,9 @@ static irqreturn_t stf_vin_isp_scd_irq_handler(int irq, void *priv)
        int_status = reg_read(ispbase, ISP_REG_ISP_CTRL_0);
 
        if (int_status & BIT(26)) {
+               vin_dev->hw_ops->isr_buffer_done(
+                       &vin_dev->line[VIN_LINE_ISP0_SCD_Y + isp_id], &params);
+
                /* clear interrupt */
                reg_write(ispbase, ISP_REG_ISP_CTRL_0, (int_status & ~EN_INT_ALL) | EN_INT_SC_DONE);
        } else
@@ -140,14 +168,31 @@ static irqreturn_t stf_vin_isp_irq_csiline_handler(int irq, void *priv)
        int_status = reg_read(ispbase, ISP_REG_ISP_CTRL_0);
        if (int_status & BIT(27)) {
                if (!atomic_read(&isp_dev->shadow_count)) {
+                       if ((int_status & BIT(11)))
+                               vin_dev->hw_ops->isr_change_buffer(
+                                       &vin_dev->line[VIN_LINE_ISP0_SS0 + isp_id]);
+                       if ((int_status & BIT(12)))
+                               vin_dev->hw_ops->isr_change_buffer(
+                                       &vin_dev->line[VIN_LINE_ISP0_SS1 + isp_id]);
                        if ((int_status & BIT(20)))
                                vin_dev->hw_ops->isr_change_buffer(
                                        &vin_dev->line[VIN_LINE_ISP0 + isp_id]);
 
+                       value = reg_read(ispbase, ISP_REG_ITIDPSR);
+                       if ((value & BIT(17)))
+                               vin_dev->hw_ops->isr_change_buffer(
+                                       &vin_dev->line[VIN_LINE_ISP0_ITIW + isp_id]);
+                       if ((value & BIT(16)))
+                               vin_dev->hw_ops->isr_change_buffer(
+                                       &vin_dev->line[VIN_LINE_ISP0_ITIR + isp_id]);
+
                        value = reg_read(ispbase, ISP_REG_CSI_MODULE_CFG);
                        if ((value & BIT(19)))
                                vin_dev->hw_ops->isr_change_buffer(
                                        &vin_dev->line[VIN_LINE_ISP0_RAW + isp_id]);
+                       if ((value & BIT(17)))
+                               vin_dev->hw_ops->isr_change_buffer(
+                                       &vin_dev->line[VIN_LINE_ISP0_SCD_Y + isp_id]);
 
                        /* shadow update */
                        reg_set_bit(ispbase, ISP_REG_CSIINTS_ADDR, 0x30000, 0x30000);
@@ -323,14 +368,76 @@ void stf_vin_isp_set_yuv_addr(struct stf_vin2_dev *vin_dev, int isp_id,
 void stf_vin_isp_set_raw_addr(struct stf_vin2_dev *vin_dev, int isp_id,
                                dma_addr_t raw_addr)
 {
-#ifdef UNUSED_CODE
        struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
        void __iomem *ispbase =
                isp_id ? vin->isp_isp1_base : vin->isp_isp0_base;
 
        reg_write(ispbase, ISP_REG_DUMP_CFG_0, raw_addr);
-       reg_set_bit(ispbase, ISP_REG_CSIINTS_ADDR, 0x3FFFF, 0x3000a);
-#endif
+}
+
+void stf_vin_isp_set_ss0_addr(struct stf_vin2_dev *vin_dev, int isp_id,
+                               dma_addr_t y_addr, dma_addr_t uv_addr)
+{
+       struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
+       void __iomem *ispbase =
+               isp_id ? vin->isp_isp1_base : vin->isp_isp0_base;
+
+       reg_write(ispbase, ISP_REG_SS0AY, y_addr);
+       reg_write(ispbase, ISP_REG_SS0AUV, uv_addr);
+}
+
+void stf_vin_isp_set_ss1_addr(struct stf_vin2_dev *vin_dev, int isp_id,
+                               dma_addr_t y_addr, dma_addr_t uv_addr)
+{
+       struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
+       void __iomem *ispbase =
+               isp_id ? vin->isp_isp1_base : vin->isp_isp0_base;
+
+       reg_write(ispbase, ISP_REG_SS1AY, y_addr);
+       reg_write(ispbase, ISP_REG_SS1AUV, uv_addr);
+}
+
+void stf_vin_isp_set_itiw_addr(struct stf_vin2_dev *vin_dev, int isp_id,
+                               dma_addr_t y_addr, dma_addr_t uv_addr)
+{
+       struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
+       void __iomem *ispbase =
+               isp_id ? vin->isp_isp1_base : vin->isp_isp0_base;
+
+       reg_write(ispbase, ISP_REG_ITIDWYSAR, y_addr);
+       reg_write(ispbase, ISP_REG_ITIDWUSAR, uv_addr);
+}
+
+void stf_vin_isp_set_itir_addr(struct stf_vin2_dev *vin_dev, int isp_id,
+                               dma_addr_t y_addr, dma_addr_t uv_addr)
+{
+       struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
+       void __iomem *ispbase =
+               isp_id ? vin->isp_isp1_base : vin->isp_isp0_base;
+
+       reg_write(ispbase, ISP_REG_ITIDRYSAR, y_addr);
+       reg_write(ispbase, ISP_REG_ITIDRUSAR, uv_addr);
+}
+
+int stf_vin_isp_get_scd_type(struct stf_vin2_dev *vin_dev, int isp_id)
+{
+       struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
+       void __iomem *ispbase =
+               isp_id ? vin->isp_isp1_base : vin->isp_isp0_base;
+
+       return (reg_read(ispbase, ISP_REG_SC_CFG_1) & (0x3 << 30)) >> 30;
+}
+
+void stf_vin_isp_set_scd_addr(struct stf_vin2_dev *vin_dev, int isp_id,
+                               dma_addr_t yhist_addr, dma_addr_t scd_addr, int scd_type)
+{
+       struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
+       void __iomem *ispbase =
+               isp_id ? vin->isp_isp1_base : vin->isp_isp0_base;
+
+       reg_set_bit(ispbase, ISP_REG_SC_CFG_1, 0x3 << 30, scd_type << 30);
+       reg_write(ispbase, ISP_REG_SCD_CFG_0, scd_addr);
+       reg_write(ispbase, ISP_REG_YHIST_CFG_4, yhist_addr);
 }
 
 void dump_vin_reg(void *__iomem regbase)
@@ -362,6 +469,12 @@ struct vin_hw_ops vin_ops = {
        .vin_wr_set_pong_addr  = stf_vin_wr_set_pong_addr,
        .vin_isp_set_yuv_addr  = stf_vin_isp_set_yuv_addr,
        .vin_isp_set_raw_addr  = stf_vin_isp_set_raw_addr,
+       .vin_isp_set_ss0_addr  = stf_vin_isp_set_ss0_addr,
+       .vin_isp_set_ss1_addr  = stf_vin_isp_set_ss1_addr,
+       .vin_isp_set_itiw_addr  = stf_vin_isp_set_itiw_addr,
+       .vin_isp_set_itir_addr  = stf_vin_isp_set_itir_addr,
+       .vin_isp_set_scd_addr  = stf_vin_isp_set_scd_addr,
+       .vin_isp_get_scd_type  = stf_vin_isp_get_scd_type,
        .vin_wr_irq_handler    = stf_vin_wr_irq_handler,
        .vin_isp_irq_handler   = stf_vin_isp_irq_handler,
        .vin_isp_csi_irq_handler   = stf_vin_isp_csi_irq_handler,
index c12ce0a..40f8cd9 100644 (file)
@@ -425,7 +425,7 @@ static int stfcamss_register_subdevices(struct stfcamss *stfcamss)
                        STF_CSIPHY_PAD_SRC,
                        &csi_dev[j].subdev.entity,
                        STF_CSI_PAD_SINK,
-                       0);
+                       MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
                if (ret < 0) {
                        st_err(ST_CAMSS,
                                "Failed to link %s->%s entities: %d\n",
@@ -455,7 +455,67 @@ static int stfcamss_register_subdevices(struct stfcamss *stfcamss)
 
                ret = media_create_pad_link(
                        &isp_dev[i].subdev.entity,
-                       STF_ISP_PAD_SRC,
+                       STF_ISP_PAD_SRC_SS0,
+                       &vin_dev->line[i + VIN_LINE_ISP0_SS0].subdev.entity,
+                       STF_VIN_PAD_SINK,
+                       0);
+               if (ret < 0) {
+                       st_err(ST_CAMSS,
+                               "Failed to link %s->%s entities: %d\n",
+                               isp_dev[i].subdev.entity.name,
+                               vin_dev->line[i + VIN_LINE_ISP0_SS0]
+                               .subdev.entity.name,
+                               ret);
+                       goto err_link;
+               }
+               ret = media_create_pad_link(
+                       &isp_dev[i].subdev.entity,
+                       STF_ISP_PAD_SRC_SS1,
+                       &vin_dev->line[i + VIN_LINE_ISP0_SS1].subdev.entity,
+                       STF_VIN_PAD_SINK,
+                       0);
+               if (ret < 0) {
+                       st_err(ST_CAMSS,
+                               "Failed to link %s->%s entities: %d\n",
+                               isp_dev[i].subdev.entity.name,
+                               vin_dev->line[i + VIN_LINE_ISP0_SS1]
+                               .subdev.entity.name,
+                               ret);
+                       goto err_link;
+               }
+               ret = media_create_pad_link(
+                       &isp_dev[i].subdev.entity,
+                       STF_ISP_PAD_SRC_ITIW,
+                       &vin_dev->line[i + VIN_LINE_ISP0_ITIW].subdev.entity,
+                       STF_VIN_PAD_SINK,
+                       0);
+               if (ret < 0) {
+                       st_err(ST_CAMSS,
+                               "Failed to link %s->%s entities: %d\n",
+                               isp_dev[i].subdev.entity.name,
+                               vin_dev->line[i + VIN_LINE_ISP0_ITIW]
+                               .subdev.entity.name,
+                               ret);
+                       goto err_link;
+               }
+               ret = media_create_pad_link(
+                       &isp_dev[i].subdev.entity,
+                       STF_ISP_PAD_SRC_ITIR,
+                       &vin_dev->line[i + VIN_LINE_ISP0_ITIR].subdev.entity,
+                       STF_VIN_PAD_SINK,
+                       0);
+               if (ret < 0) {
+                       st_err(ST_CAMSS,
+                               "Failed to link %s->%s entities: %d\n",
+                               isp_dev[i].subdev.entity.name,
+                               vin_dev->line[i + VIN_LINE_ISP0_ITIR]
+                               .subdev.entity.name,
+                               ret);
+                       goto err_link;
+               }
+               ret = media_create_pad_link(
+                       &isp_dev[i].subdev.entity,
+                       STF_ISP_PAD_SRC_RAW,
                        &vin_dev->line[i + VIN_LINE_ISP0_RAW].subdev.entity,
                        STF_VIN_PAD_SINK,
                        0);
@@ -468,7 +528,21 @@ static int stfcamss_register_subdevices(struct stfcamss *stfcamss)
                                ret);
                        goto err_link;
                }
-
+               ret = media_create_pad_link(
+                       &isp_dev[i].subdev.entity,
+                       STF_ISP_PAD_SRC_SCD_Y,
+                       &vin_dev->line[i + VIN_LINE_ISP0_SCD_Y].subdev.entity,
+                       STF_VIN_PAD_SINK,
+                       0);
+               if (ret < 0) {
+                       st_err(ST_CAMSS,
+                               "Failed to link %s->%s entities: %d\n",
+                               isp_dev[i].subdev.entity.name,
+                               vin_dev->line[i + VIN_LINE_ISP0_SCD_Y]
+                               .subdev.entity.name,
+                               ret);
+                       goto err_link;
+               }
                ret = media_create_pad_link(
                        &dvp_dev->subdev.entity,
                        STF_DVP_PAD_SRC,
@@ -688,7 +762,6 @@ static int stfcamss_subdev_notifier_complete(
 static const struct v4l2_async_notifier_operations
 stfcamss_subdev_notifier_ops = {
        .bound = stfcamss_subdev_notifier_bound,
-       // .complete = stfcamss_subdev_notifier_complete,
 };
 
 static const struct media_device_ops stfcamss_media_ops = {
index 095d210..fe6ebc3 100755 (executable)
@@ -84,6 +84,7 @@ struct stfcamss {
        struct stf_vin_dev *vin;  // stfcamss phy res
        struct v4l2_device v4l2_dev;
        struct media_device media_dev;
+       struct media_pipeline pipe;
        struct device *dev;
        struct stf_vin2_dev *vin_dev;  // subdev
        struct stf_dvp_dev *dvp_dev;   // subdev