v4l2: ISP multi stream set format
authorliuxl0327 <liuxl0327@starfivetech.com>
Mon, 21 Mar 2022 10:17:05 +0000 (18:17 +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_csi.c
drivers/media/platform/starfive/v4l2_driver/stf_csiphy.c
drivers/media/platform/starfive/v4l2_driver/stf_dvp.c
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_isp_hw_ops.c
drivers/media/platform/starfive/v4l2_driver/stf_video.c
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

index 967e2cc..2066285 100644 (file)
@@ -145,7 +145,8 @@ static void csi_try_format(struct stf_csi_dev *csi_dev,
                fmt->height = clamp_t(u32,
                                fmt->height,
                                STFCAMSS_FRAME_MIN_HEIGHT,
-                               STFCAMSS_FRAME_MAX_HEIGHT_PIX);
+                               STFCAMSS_FRAME_MAX_HEIGHT);
+
 
                fmt->field = V4L2_FIELD_NONE;
                fmt->colorspace = V4L2_COLORSPACE_SRGB;
index 76ccb2d..bd0d148 100644 (file)
@@ -116,7 +116,7 @@ static void csiphy_try_format(struct stf_csiphy_dev *csiphy_dev,
                fmt->height = clamp_t(u32,
                                fmt->height,
                                STFCAMSS_FRAME_MIN_HEIGHT,
-                               STFCAMSS_FRAME_MAX_HEIGHT_PIX);
+                               STFCAMSS_FRAME_MAX_HEIGHT);
 
                fmt->field = V4L2_FIELD_NONE;
                fmt->colorspace = V4L2_COLORSPACE_SRGB;
index f7151fc..ef15d38 100644 (file)
@@ -125,10 +125,11 @@ static void dvp_try_format(struct stf_dvp_dev *dvp_dev,
                        fmt->code = dvp_dev->formats[0].code;
 
                fmt->width = clamp_t(u32,
-                               fmt->width, STFCAMSS_FRAME_MIN_WIDTH, STFCAMSS_FRAME_MAX_WIDTH);
+                               fmt->width, STFCAMSS_FRAME_MIN_WIDTH,
+                               STFCAMSS_FRAME_MAX_WIDTH);
                fmt->height = clamp_t(u32,
                                fmt->height, STFCAMSS_FRAME_MIN_HEIGHT,
-                               STFCAMSS_FRAME_MAX_HEIGHT_PIX);
+                               STFCAMSS_FRAME_MAX_HEIGHT);
 
                fmt->field = V4L2_FIELD_NONE;
                fmt->colorspace = V4L2_COLORSPACE_SRGB;
index 93bacaf..761ffd5 100644 (file)
 #include "stf_dmabuf.h"
 
 static int user_config_isp;
+static int isp_set_selection(struct v4l2_subdev *sd,
+                            struct v4l2_subdev_state *state,
+                            struct v4l2_subdev_selection *sel);
+
+static struct v4l2_rect *
+__isp_get_compose(struct stf_isp_dev *isp_dev,
+                 struct v4l2_subdev_state *state,
+                 enum v4l2_subdev_format_whence which);
+
+static struct v4l2_rect *
+__isp_get_crop(struct stf_isp_dev *isp_dev,
+               struct v4l2_subdev_state *state,
+               enum v4l2_subdev_format_whence which);
+
+static struct v4l2_rect *
+__isp_get_scale(struct stf_isp_dev *isp_dev,
+               struct v4l2_subdev_state *state,
+               struct v4l2_subdev_selection *sel);
 
-static const struct isp_format isp_formats_st7110[] = {
-       { MEDIA_BUS_FMT_YUYV8_2X8, 16},
-       { MEDIA_BUS_FMT_RGB565_2X8_LE, 16},
-       { MEDIA_BUS_FMT_SRGGB10_1X10, 12},
-       { MEDIA_BUS_FMT_SGRBG10_1X10, 12},
-       { MEDIA_BUS_FMT_SGBRG10_1X10, 12},
-       { MEDIA_BUS_FMT_SBGGR10_1X10, 12},
+static struct v4l2_rect *
+__isp_get_itiws(struct stf_isp_dev *isp_dev,
+               struct v4l2_subdev_state *state,
+               enum v4l2_subdev_format_whence which);
+
+// sink format and raw format must one by one
+static const struct isp_format isp_formats_st7110_sink[] = {
+       { MEDIA_BUS_FMT_SRGGB10_1X10, 10},
+       { MEDIA_BUS_FMT_SGRBG10_1X10, 10},
+       { MEDIA_BUS_FMT_SGBRG10_1X10, 10},
+       { MEDIA_BUS_FMT_SBGGR10_1X10, 10},
+};
+
+static const struct isp_format isp_formats_st7110_raw[] = {
+       { MEDIA_BUS_FMT_SRGGB12_1X12, 12},
+       { MEDIA_BUS_FMT_SGRBG12_1X12, 12},
+       { MEDIA_BUS_FMT_SGBRG12_1X12, 12},
+       { MEDIA_BUS_FMT_SBGGR12_1X12, 12},
+};
+
+static const struct isp_format isp_formats_st7110_uo[] = {
+       { MEDIA_BUS_FMT_Y12_1X12, 8},
+};
+
+static const struct isp_format isp_formats_st7110_iti[] = {
+       { MEDIA_BUS_FMT_SRGGB10_1X10, 10},
+       { MEDIA_BUS_FMT_SGRBG10_1X10, 10},
+       { MEDIA_BUS_FMT_SGBRG10_1X10, 10},
+       { MEDIA_BUS_FMT_SBGGR10_1X10, 10},
+       { MEDIA_BUS_FMT_SRGGB12_1X12, 12},
+       { MEDIA_BUS_FMT_SGRBG12_1X12, 12},
+       { MEDIA_BUS_FMT_SGBRG12_1X12, 12},
+       { MEDIA_BUS_FMT_SBGGR12_1X12, 12},
+       { MEDIA_BUS_FMT_Y12_1X12, 8},
+       { MEDIA_BUS_FMT_YUV8_1X24, 8},
+};
+
+#define SINK_FORMATS_INDEX    0
+#define UO_FORMATS_INDEX      1
+#define ITI_FORMATS_INDEX     2
+#define RAW_FORMATS_INDEX     3
+
+static const struct isp_format_table isp_formats_st7110[] = {
+       { isp_formats_st7110_sink, ARRAY_SIZE(isp_formats_st7110_sink) }, // 0
+       { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) },     // 1
+       { isp_formats_st7110_iti, ARRAY_SIZE(isp_formats_st7110_iti) },   // 2
+       { isp_formats_st7110_raw, ARRAY_SIZE(isp_formats_st7110_raw) },   // 3
 };
 
 int stf_isp_subdev_init(struct stfcamss *stfcamss, int id)
@@ -367,19 +425,45 @@ __isp_get_format(struct stf_isp_dev *isp_dev,
        return &isp_dev->fmt[pad];
 }
 
+static int isp_get_interface_type(struct media_entity *entity)
+{
+       struct v4l2_subdev *subdev;
+       struct media_pad *pad = &entity->pads[0];
+
+       if (!(pad->flags & MEDIA_PAD_FL_SINK))
+               return -EINVAL;
+
+       pad = media_entity_remote_pad(pad);
+       if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+               return -EINVAL;
+
+       subdev = media_entity_to_v4l2_subdev(pad->entity);
+
+       st_debug(ST_ISP, "interface subdev name %s\n", subdev->name);
+       if (!strncmp(subdev->name, STF_CSI_NAME, strlen(STF_CSI_NAME)))
+               return CSI_SENSOR;
+       if (!strncmp(subdev->name, STF_DVP_NAME, strlen(STF_DVP_NAME)))
+               return DVP_SENSOR;
+       return -EINVAL;
+}
+
 static int isp_set_stream(struct v4l2_subdev *sd, int enable)
 {
        struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
-       int ret = 0;
+       int ret = 0, interface_type;
        struct v4l2_mbus_framefmt *fmt;
 
        fmt = __isp_get_format(isp_dev, NULL, STF_ISP_PAD_SINK, V4L2_SUBDEV_FORMAT_ACTIVE);
        mutex_lock(&isp_dev->stream_lock);
        if (enable) {
                if (isp_dev->stream_count == 0) {
+                       interface_type = isp_get_interface_type(&sd->entity);
+                       if (interface_type < 0) {
+                               st_err(ST_ISP, "%s, pipeline not config\n", __func__);
+                               goto exit;
+                       }
                        isp_dev->hw_ops->isp_set_format(isp_dev,
-                                       &isp_dev->crop, fmt->code);
-                               // format->width, format->height);
+                                       isp_dev->rect, fmt->code, interface_type);
                        isp_dev->hw_ops->isp_reset(isp_dev);
                        isp_dev->hw_ops->isp_stream_set(isp_dev, enable);
                        user_config_isp = 0;
@@ -412,24 +496,23 @@ static void isp_try_format(struct stf_isp_dev *isp_dev,
                        struct v4l2_mbus_framefmt *fmt,
                        enum v4l2_subdev_format_whence which)
 {
+       const struct isp_format_table *formats;
        unsigned int i;
+       u32 code = fmt->code;
+       u32 bpp;
 
        switch (pad) {
        case STF_ISP_PAD_SINK:
                /* Set format on sink pad */
 
-               for (i = 0; i < isp_dev->nformats; i++)
-                       if (fmt->code == isp_dev->formats[i].code)
-                               break;
-
-               if (i >= isp_dev->nformats)
-                       fmt->code = MEDIA_BUS_FMT_RGB565_2X8_LE;
-
+               formats = &isp_dev->formats[SINK_FORMATS_INDEX];
                fmt->width = clamp_t(u32,
-                               fmt->width, 8, STFCAMSS_FRAME_MAX_WIDTH);
-               fmt->width &= ~0x7;
+                               fmt->width, STFCAMSS_FRAME_MIN_WIDTH,
+                               STFCAMSS_FRAME_MAX_WIDTH);
                fmt->height = clamp_t(u32,
-                               fmt->height, 1, STFCAMSS_FRAME_MAX_HEIGHT_PIX);
+                               fmt->height, STFCAMSS_FRAME_MIN_HEIGHT,
+                               STFCAMSS_FRAME_MAX_HEIGHT);
+               fmt->height &= ~0x1;
 
                fmt->field = V4L2_FIELD_NONE;
                fmt->colorspace = V4L2_COLORSPACE_SRGB;
@@ -438,9 +521,68 @@ static void isp_try_format(struct stf_isp_dev *isp_dev,
                break;
 
        case STF_ISP_PAD_SRC:
+       case STF_ISP_PAD_SRC_SS0:
+       case STF_ISP_PAD_SRC_SS1:
+               formats = &isp_dev->formats[UO_FORMATS_INDEX];
+               break;
+
+       case STF_ISP_PAD_SRC_ITIW:
+       case STF_ISP_PAD_SRC_ITIR:
+               formats = &isp_dev->formats[ITI_FORMATS_INDEX];
+               break;
 
+       case STF_ISP_PAD_SRC_RAW:
+       case STF_ISP_PAD_SRC_SCD_Y:
+               formats = &isp_dev->formats[RAW_FORMATS_INDEX];
+               break;
+       }
+
+       for (i = 0; i < formats->nfmts; i++)
+               if (fmt->code == formats->fmts[i].code)
+                       break;
+
+       if (pad != STF_ISP_PAD_SINK)
                *fmt = *__isp_get_format(isp_dev, state, STF_ISP_PAD_SINK, which);
 
+       if (i >= formats->nfmts) {
+               fmt->code = formats->fmts[0].code;
+               bpp = formats->fmts[0].bpp;
+       } else {
+               // sink format and raw format must one by one
+               if (pad == STF_ISP_PAD_SRC_RAW) {
+                       formats = &isp_dev->formats[SINK_FORMATS_INDEX];
+                       for (i = 0; i < formats->nfmts; i++)
+                               if (fmt->code == formats->fmts[i].code)
+                                       break;
+                       formats = &isp_dev->formats[RAW_FORMATS_INDEX];
+                       fmt->code = formats->fmts[i].code;
+                       bpp = formats->fmts[i].bpp;
+               } else {
+                       fmt->code = code;
+                       bpp = formats->fmts[i].bpp;
+               }
+       }
+
+       switch (pad) {
+       case STF_ISP_PAD_SINK:
+               break;
+       case STF_ISP_PAD_SRC:
+               isp_dev->rect[ISP_COMPOSE].bpp = bpp;
+               break;
+       case STF_ISP_PAD_SRC_SS0:
+               isp_dev->rect[ISP_SCALE_SS0].bpp = bpp;
+               break;
+       case STF_ISP_PAD_SRC_SS1:
+               isp_dev->rect[ISP_SCALE_SS1].bpp = bpp;
+               break;
+       case STF_ISP_PAD_SRC_ITIW:
+       case STF_ISP_PAD_SRC_ITIR:
+               isp_dev->rect[ISP_ITIWS].bpp = bpp;
+               break;
+       case STF_ISP_PAD_SRC_RAW:
+               isp_dev->rect[ISP_CROP].bpp = bpp;
+               break;
+       case STF_ISP_PAD_SRC_SCD_Y:
                break;
        }
 }
@@ -450,11 +592,13 @@ static int isp_enum_mbus_code(struct v4l2_subdev *sd,
                        struct v4l2_subdev_mbus_code_enum *code)
 {
        struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
+       const struct isp_format_table *formats;
 
        if (code->index >= isp_dev->nformats)
                return -EINVAL;
        if (code->pad == STF_ISP_PAD_SINK) {
-               code->code = isp_dev->formats[code->index].code;
+               formats = &isp_dev->formats[SINK_FORMATS_INDEX];
+               code->code = formats->fmts[code->index].code;
        } else {
                struct v4l2_mbus_framefmt *sink_fmt;
 
@@ -516,48 +660,73 @@ static int isp_get_format(struct v4l2_subdev *sd,
        return 0;
 }
 
-static int isp_set_selection(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_state *state,
-                            struct v4l2_subdev_selection *sel);
-
 static int isp_set_format(struct v4l2_subdev *sd,
                        struct v4l2_subdev_state *state,
                        struct v4l2_subdev_format *fmt)
 {
        struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
+       struct v4l2_subdev_selection sel = { 0 };
+       struct v4l2_rect *rect = NULL;
+       int ret;
 
        format = __isp_get_format(isp_dev, state, fmt->pad, fmt->which);
        if (format == NULL)
                return -EINVAL;
 
-       isp_try_format(isp_dev, state, fmt->pad, &fmt->format, fmt->which);
-       *format = fmt->format;
+       mutex_lock(&isp_dev->stream_lock);
+       if (isp_dev->stream_count) {
+               fmt->format = *format;
+               if (fmt->reserved[0] != 0) {
+                       sel.which = fmt->which;
+                       sel.pad = fmt->reserved[0];
+
+                       switch (fmt->reserved[0]) {
+                       case STF_ISP_PAD_SRC:
+                               rect = __isp_get_compose(isp_dev, state, fmt->which);
+                               break;
+                       case STF_ISP_PAD_SRC_SS0:
+                       case STF_ISP_PAD_SRC_SS1:
+                               rect = __isp_get_scale(isp_dev, state, &sel);
+                               break;
+                       case STF_ISP_PAD_SRC_ITIW:
+                       case STF_ISP_PAD_SRC_ITIR:
+                               rect = __isp_get_itiws(isp_dev, state, fmt->which);
+                               break;
+                       case STF_ISP_PAD_SRC_RAW:
+                       case STF_ISP_PAD_SRC_SCD_Y:
+                               rect = __isp_get_crop(isp_dev, state, fmt->which);
+                               break;
+                       default:
+                               break;
+                       }
+                       if (rect != NULL) {
+                               fmt->format.width = rect->width;
+                               fmt->format.height = rect->height;
+                       }
+               }
+               mutex_unlock(&isp_dev->stream_lock);
+               goto out;
+       } else {
+               isp_try_format(isp_dev, state, fmt->pad, &fmt->format, fmt->which);
+               *format = fmt->format;
+       }
+       mutex_unlock(&isp_dev->stream_lock);
 
        /* Propagate the format from sink to source */
        if (fmt->pad == STF_ISP_PAD_SINK) {
-               struct v4l2_subdev_selection sel = { 0 };
-               int ret;
-
-               format = __isp_get_format(isp_dev, state, STF_ISP_PAD_SRC,
-                                       fmt->which);
-
-               *format = fmt->format;
-               isp_try_format(isp_dev, state, STF_ISP_PAD_SRC, format,
-                                       fmt->which);
-
                /* Reset sink pad compose selection */
                sel.which = fmt->which;
                sel.pad = STF_ISP_PAD_SINK;
-               sel.target = V4L2_SEL_TGT_COMPOSE;
+               sel.target = V4L2_SEL_TGT_CROP;
                sel.r.width = fmt->format.width;
                sel.r.height = fmt->format.height;
                ret = isp_set_selection(sd, state, &sel);
                if (ret < 0)
                        return ret;
-
        }
 
+out:
        return 0;
 }
 
@@ -570,22 +739,51 @@ __isp_get_compose(struct stf_isp_dev *isp_dev,
                return v4l2_subdev_get_try_compose(&isp_dev->subdev, state,
                                                   STF_ISP_PAD_SINK);
 
-       return &isp_dev->compose;
+
+       return &isp_dev->rect[ISP_COMPOSE].rect;
 }
 
 static struct v4l2_rect *
 __isp_get_crop(struct stf_isp_dev *isp_dev,
-              struct v4l2_subdev_state *state,
-              enum v4l2_subdev_format_whence which)
+               struct v4l2_subdev_state *state,
+               enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
                return v4l2_subdev_get_try_crop(&isp_dev->subdev, state,
-                                               STF_ISP_PAD_SRC);
+                                               STF_ISP_PAD_SINK);
 
-       return &isp_dev->crop;
+       return &isp_dev->rect[ISP_CROP].rect;
 }
 
-static void isp_try_compose(struct stf_isp_dev *isp_dev,
+static struct v4l2_rect *
+__isp_get_scale(struct stf_isp_dev *isp_dev,
+               struct v4l2_subdev_state *state,
+               struct v4l2_subdev_selection *sel)
+{
+       int pad;
+
+       if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
+               return v4l2_subdev_get_try_compose(&isp_dev->subdev, state,
+                                               STF_ISP_PAD_SINK);
+       if (sel->pad != STF_ISP_PAD_SRC_SS0 && sel->pad != STF_ISP_PAD_SRC_SS1)
+               return NULL;
+
+       pad = sel->pad == STF_ISP_PAD_SRC_SS0 ? ISP_SCALE_SS0 : ISP_SCALE_SS1;
+       return &isp_dev->rect[pad].rect;
+}
+
+static struct v4l2_rect *
+__isp_get_itiws(struct stf_isp_dev *isp_dev,
+               struct v4l2_subdev_state *state,
+               enum v4l2_subdev_format_whence which)
+{
+       if (which == V4L2_SUBDEV_FORMAT_TRY)
+               return v4l2_subdev_get_try_crop(&isp_dev->subdev, state, STF_ISP_PAD_SINK);
+
+       return &isp_dev->rect[ISP_ITIWS].rect;
+}
+
+static void isp_try_crop(struct stf_isp_dev *isp_dev,
                            struct v4l2_subdev_state *state,
                            struct v4l2_rect *rect,
                            enum v4l2_subdev_format_whence which)
@@ -597,31 +795,63 @@ static void isp_try_compose(struct stf_isp_dev *isp_dev,
        if (rect->width > fmt->width)
                rect->width = fmt->width;
 
+       if (rect->width + rect->left > fmt->width)
+               rect->left = fmt->width - rect->width;
+
        if (rect->height > fmt->height)
                rect->height = fmt->height;
 
-       if (fmt->width > rect->width * SCALER_RATIO_MAX)
-               rect->width = (fmt->width + SCALER_RATIO_MAX - 1) /
-                                                       SCALER_RATIO_MAX;
+       if (rect->height + rect->top > fmt->height)
+               rect->top = fmt->height - rect->height;
 
-       rect->width &= ~0x7;
-
-       if (fmt->height > rect->height * SCALER_RATIO_MAX)
-               rect->height = (fmt->height + SCALER_RATIO_MAX - 1) /
-                                                       SCALER_RATIO_MAX;
-
-       if (rect->width < 16)
-               rect->width = 16;
+       if (rect->width < STFCAMSS_FRAME_MIN_WIDTH) {
+               rect->left = 0;
+               rect->width = STFCAMSS_FRAME_MIN_WIDTH;
+       }
 
-       if (rect->height < 4)
-               rect->height = 4;
+       if (rect->height < STFCAMSS_FRAME_MIN_HEIGHT) {
+               rect->top = 0;
+               rect->height = STFCAMSS_FRAME_MIN_HEIGHT;
+       }
+       rect->height &= ~0x1;
 }
 
-static void isp_try_crop(struct stf_isp_dev *isp_dev,
+static void isp_try_compose(struct stf_isp_dev *isp_dev,
                         struct v4l2_subdev_state *state,
                         struct v4l2_rect *rect,
                         enum v4l2_subdev_format_whence which)
 {
+       struct v4l2_rect *crop;
+
+       crop = __isp_get_crop(isp_dev, state, which);
+
+       if (rect->width > crop->width)
+               rect->width = crop->width;
+
+       if (rect->height > crop->height)
+               rect->height = crop->height;
+
+       if (crop->width > rect->width * SCALER_RATIO_MAX)
+               rect->width = (crop->width + SCALER_RATIO_MAX - 1) /
+                                                       SCALER_RATIO_MAX;
+
+       if (crop->height > rect->height * SCALER_RATIO_MAX)
+               rect->height = (crop->height + SCALER_RATIO_MAX - 1) /
+                                                       SCALER_RATIO_MAX;
+
+       if (rect->width < STFCAMSS_FRAME_MIN_WIDTH)
+               rect->width = STFCAMSS_FRAME_MIN_WIDTH;
+
+       if (rect->height < STFCAMSS_FRAME_MIN_HEIGHT)
+               rect->height = STFCAMSS_FRAME_MIN_HEIGHT;
+       rect->height &= ~0x1;
+}
+
+static void isp_try_scale(struct stf_isp_dev *isp_dev,
+                           struct v4l2_subdev_state *state,
+                           struct v4l2_rect *rect,
+                           enum v4l2_subdev_format_whence which)
+{
        struct v4l2_rect *compose;
 
        compose = __isp_get_compose(isp_dev, state, which);
@@ -638,20 +868,49 @@ static void isp_try_crop(struct stf_isp_dev *isp_dev,
        if (rect->height + rect->top > compose->height)
                rect->top = compose->height - rect->height;
 
-       // /* isp in line based mode writes multiple of 16 horizontally */
-       rect->left &= ~0x1;
-       rect->top &= ~0x1;
-       rect->width &= ~0x7;
+       if (rect->width < STFCAMSS_FRAME_MIN_WIDTH) {
+               rect->left = 0;
+               rect->width = STFCAMSS_FRAME_MIN_WIDTH;
+       }
+
+       if (rect->height < STFCAMSS_FRAME_MIN_HEIGHT) {
+               rect->top = 0;
+               rect->height = STFCAMSS_FRAME_MIN_HEIGHT;
+       }
+       rect->height &= ~0x1;
+}
+
+static void isp_try_itiws(struct stf_isp_dev *isp_dev,
+                           struct v4l2_subdev_state *state,
+                           struct v4l2_rect *rect,
+                           enum v4l2_subdev_format_whence which)
+{
+       struct v4l2_rect *crop;
+
+       crop = __isp_get_crop(isp_dev, state, which);
+
+       if (rect->width > crop->width)
+               rect->width = crop->width;
+
+       if (rect->width + rect->left > crop->width)
+               rect->left = crop->width - rect->width;
+
+       if (rect->height > crop->height)
+               rect->height = crop->height;
+
+       if (rect->height + rect->top > crop->height)
+               rect->top = crop->height - rect->height;
 
-       if (rect->width < 16) {
+       if (rect->width < STFCAMSS_FRAME_MIN_WIDTH) {
                rect->left = 0;
-               rect->width = 16;
+               rect->width = STFCAMSS_FRAME_MIN_WIDTH;
        }
 
-       if (rect->height < 4) {
+       if (rect->height < STFCAMSS_FRAME_MIN_HEIGHT) {
                rect->top = 0;
-               rect->height = 4;
+               rect->height = STFCAMSS_FRAME_MIN_HEIGHT;
        }
+       rect->height &= ~0x1;
 }
 
 static int isp_get_selection(struct v4l2_subdev *sd,
@@ -664,8 +923,8 @@ static int isp_get_selection(struct v4l2_subdev *sd,
        int ret;
 
        switch (sel->target) {
-       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
-       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_CROP_DEFAULT:
                fmt.pad = sel->pad;
                fmt.which = sel->which;
                ret = isp_get_format(sd, state, &fmt);
@@ -677,16 +936,18 @@ static int isp_get_selection(struct v4l2_subdev *sd,
                sel->r.width = fmt.format.width;
                sel->r.height = fmt.format.height;
                break;
-       case V4L2_SEL_TGT_COMPOSE:
-               rect = __isp_get_compose(isp_dev, state, sel->which);
+       case V4L2_SEL_TGT_CROP:
+               rect = __isp_get_crop(isp_dev, state, sel->which);
                if (rect == NULL)
                        return -EINVAL;
 
                sel->r = *rect;
                break;
-       case V4L2_SEL_TGT_CROP_BOUNDS:
-       case V4L2_SEL_TGT_CROP_DEFAULT:
-               rect = __isp_get_compose(isp_dev, state, sel->which);
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+               if (sel->pad > STF_ISP_PAD_SRC_ITIR)
+                       return -EINVAL;
+               rect = __isp_get_crop(isp_dev, state, sel->which);
                if (rect == NULL)
                        return -EINVAL;
 
@@ -695,19 +956,32 @@ static int isp_get_selection(struct v4l2_subdev *sd,
                sel->r.width = rect->width;
                sel->r.height = rect->height;
                break;
-       case V4L2_SEL_TGT_CROP:
-               rect = __isp_get_crop(isp_dev, state, sel->which);
-               if (rect == NULL)
+       case V4L2_SEL_TGT_COMPOSE:
+               if (sel->pad > STF_ISP_PAD_SRC_ITIR)
                        return -EINVAL;
-
+               if (sel->pad == STF_ISP_PAD_SRC_SS0
+                       || sel->pad == STF_ISP_PAD_SRC_SS1) {
+                       rect = __isp_get_scale(isp_dev, state, sel);
+                       if (rect == NULL)
+                               return -EINVAL;
+               } else if (sel->pad == STF_ISP_PAD_SRC_ITIW
+                       || sel->pad == STF_ISP_PAD_SRC_ITIR) {
+                       rect = __isp_get_itiws(isp_dev, state, sel->which);
+                       if (rect == NULL)
+                               return -EINVAL;
+               } else {
+                       rect = __isp_get_compose(isp_dev, state, sel->which);
+                       if (rect == NULL)
+                               return -EINVAL;
+               }
                sel->r = *rect;
                break;
        default:
                return -EINVAL;
        }
 
-       st_info(ST_ISP, "get left = %d, %d, %d, %d\n",
-                       sel->r.left, sel->r.top, sel->r.width, sel->r.height);
+       st_info(ST_ISP, "%s pad = %d, left = %d, %d, %d, %d\n",
+                       __func__, sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height);
        return 0;
 }
 
@@ -717,40 +991,106 @@ static int isp_set_selection(struct v4l2_subdev *sd,
 {
        struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
        struct v4l2_rect *rect;
-       int ret;
+       int ret = 0;
 
-       st_info(ST_ISP, "left = %d, %d, %d, %d\n",
-                       sel->r.left, sel->r.top, sel->r.width, sel->r.height);
-       if (sel->target == V4L2_SEL_TGT_COMPOSE) {
-               struct v4l2_subdev_selection crop = { 0 };
+       if (sel->target == V4L2_SEL_TGT_COMPOSE &&
+                       ((sel->pad == STF_ISP_PAD_SINK)
+                        || (sel->pad == STF_ISP_PAD_SRC))) {
+               struct v4l2_subdev_format fmt = { 0 };
+               int i;
 
                rect = __isp_get_compose(isp_dev, state, sel->which);
                if (rect == NULL)
                        return -EINVAL;
 
-               isp_try_compose(isp_dev, state, &sel->r, sel->which);
-               *rect = sel->r;
+               mutex_lock(&isp_dev->stream_lock);
+               if (isp_dev->stream_count) {
+                       sel->r = *rect;
+                       mutex_unlock(&isp_dev->stream_lock);
+                       ret = 0;
+                       goto out;
+               } else {
+                       isp_try_compose(isp_dev, state, &sel->r, sel->which);
+                       *rect = sel->r;
+               }
+               mutex_unlock(&isp_dev->stream_lock);
 
-               /* Reset source crop selection */
-               crop.which = sel->which;
-               crop.pad = STF_ISP_PAD_SRC;
-               crop.target = V4L2_SEL_TGT_CROP;
-               crop.r = *rect;
-               ret = isp_set_selection(sd, state, &crop);
-       } else if (sel->target == V4L2_SEL_TGT_CROP) {
+               /* Reset source pad format width and height */
+               fmt.which = sel->which;
+               fmt.pad = STF_ISP_PAD_SRC;
+               ret = isp_get_format(sd, state, &fmt);
+               if (ret < 0)
+                       return ret;
+
+               fmt.format.width = rect->width;
+               fmt.format.height = rect->height;
+               ret = isp_set_format(sd, state, &fmt);
+
+               /* Reset scale */
+               for (i = STF_ISP_PAD_SRC_SS0; i <= STF_ISP_PAD_SRC_ITIR; i++) {
+                       struct v4l2_subdev_selection scale = { 0 };
+
+                       scale.which = sel->which;
+                       scale.target = V4L2_SEL_TGT_COMPOSE;
+                       scale.r = *rect;
+                       scale.pad = i;
+                       ret = isp_set_selection(sd, state, &scale);
+               }
+       } else if (sel->target == V4L2_SEL_TGT_COMPOSE
+                       && ((sel->pad == STF_ISP_PAD_SRC_SS0)
+                               || (sel->pad == STF_ISP_PAD_SRC_SS1))) {
                struct v4l2_subdev_format fmt = { 0 };
 
-               rect = __isp_get_crop(isp_dev, state, sel->which);
+               rect = __isp_get_scale(isp_dev, state, sel);
                if (rect == NULL)
                        return -EINVAL;
 
-               isp_try_crop(isp_dev, state, &sel->r, sel->which);
+               mutex_lock(&isp_dev->stream_lock);
+               if (isp_dev->stream_count) {
+                       sel->r = *rect;
+                       mutex_unlock(&isp_dev->stream_lock);
+                       ret = 0;
+                       goto out;
+               } else {
+                       isp_try_scale(isp_dev, state, &sel->r, sel->which);
+                       *rect = sel->r;
+               }
+               mutex_unlock(&isp_dev->stream_lock);
+
+               /* Reset source pad format width and height */
+               fmt.which = sel->which;
+               fmt.pad = sel->pad;
+               ret = isp_get_format(sd, state, &fmt);
+               if (ret < 0)
+                       return ret;
+
+               fmt.format.width = rect->width;
+               fmt.format.height = rect->height;
+               ret = isp_set_format(sd, state, &fmt);
+       } else if (sel->target == V4L2_SEL_TGT_COMPOSE
+                       && ((sel->pad == STF_ISP_PAD_SRC_ITIW)
+                               || (sel->pad == STF_ISP_PAD_SRC_ITIR))) {
+               struct v4l2_subdev_format fmt = { 0 };
+
+               rect = __isp_get_itiws(isp_dev, state, sel->which);
+               if (rect == NULL)
+                       return -EINVAL;
 
-               *rect = sel->r;
+               mutex_lock(&isp_dev->stream_lock);
+               if (isp_dev->stream_count) {
+                       sel->r = *rect;
+                       mutex_unlock(&isp_dev->stream_lock);
+                       ret = 0;
+                       goto out;
+               } else {
+                       isp_try_itiws(isp_dev, state, &sel->r, sel->which);
+                       *rect = sel->r;
+               }
+               mutex_unlock(&isp_dev->stream_lock);
 
                /* Reset source pad format width and height */
                fmt.which = sel->which;
-               fmt.pad = STF_ISP_PAD_SRC;
+               fmt.pad = sel->pad;
                ret = isp_get_format(sd, state, &fmt);
                if (ret < 0)
                        return ret;
@@ -758,12 +1098,55 @@ static int isp_set_selection(struct v4l2_subdev *sd,
                fmt.format.width = rect->width;
                fmt.format.height = rect->height;
                ret = isp_set_format(sd, state, &fmt);
+       } else if (sel->target == V4L2_SEL_TGT_CROP) {
+               struct v4l2_subdev_selection compose = { 0 };
+               int i;
+
+               rect = __isp_get_crop(isp_dev, state, sel->which);
+               if (rect == NULL)
+                       return -EINVAL;
+
+               mutex_lock(&isp_dev->stream_lock);
+               if (isp_dev->stream_count) {
+                       sel->r = *rect;
+                       mutex_unlock(&isp_dev->stream_lock);
+                       ret = 0;
+                       goto out;
+               } else {
+                       isp_try_crop(isp_dev, state, &sel->r, sel->which);
+                       *rect = sel->r;
+               }
+               mutex_unlock(&isp_dev->stream_lock);
+
+               /* Reset source compose selection */
+               compose.which = sel->which;
+               compose.target = V4L2_SEL_TGT_COMPOSE;
+               compose.r.width = rect->width;
+               compose.r.height = rect->height;
+               compose.pad = STF_ISP_PAD_SINK;
+               ret = isp_set_selection(sd, state, &compose);
+
+               /* Reset source pad format width and height */
+               for (i = STF_ISP_PAD_SRC_RAW; i < STF_ISP_PADS_NUM; i++) {
+                       struct v4l2_subdev_format fmt = { 0 };
+
+                       fmt.which = sel->which;
+                       fmt.pad = i;
+                       ret = isp_get_format(sd, state, &fmt);
+                       if (ret < 0)
+                               return ret;
+
+                       fmt.format.width = rect->width;
+                       fmt.format.height = rect->height;
+                       ret = isp_set_format(sd, state, &fmt);
+               }
        } else {
                ret = -EINVAL;
        }
 
-       st_info(ST_ISP, "out left = %d, %d, %d, %d\n",
-                       sel->r.left, sel->r.top, sel->r.width, sel->r.height);
+       st_info(ST_ISP, "%s pad = %d, left = %d, %d, %d, %d\n",
+                       __func__, sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height);
+out:
        return ret;
 }
 
index 97c3b2c..d8a8cb5 100644 (file)
@@ -94,6 +94,11 @@ struct isp_format {
        u8 bpp;
 };
 
+struct isp_format_table {
+       const struct isp_format *fmts;
+       int nfmts;
+};
+
 struct regval_t {
        u32 addr;
        u32 val;
@@ -106,6 +111,11 @@ struct reg_table {
        int regval_num;
 };
 
+struct isp_stream_format {
+       struct v4l2_rect rect;
+       u32 bpp;
+};
+
 struct stf_isp_dev;
 enum subdev_type;
 
@@ -115,7 +125,8 @@ struct isp_hw_ops {
        int (*isp_reset)(struct stf_isp_dev *isp_dev);
        int (*isp_config_set)(struct stf_isp_dev *isp_dev);
        int (*isp_set_format)(struct stf_isp_dev *isp_dev,
-                       struct v4l2_rect *crop, u32 mcode);
+                       struct isp_stream_format *crop, u32 mcode,
+                       int type);
                        // u32 width, u32 height);
        int (*isp_stream_set)(struct stf_isp_dev *isp_dev, int on);
        int (*isp_reg_read)(struct stf_isp_dev *isp_dev, void *arg);
@@ -156,17 +167,24 @@ struct isp_setfile {
        unsigned int state;
 };
 
+enum {
+       ISP_CROP = 0,
+       ISP_COMPOSE,
+       ISP_SCALE_SS0,
+       ISP_SCALE_SS1,
+       ISP_ITIWS,
+       ISP_RECT_MAX
+};
+
 struct stf_isp_dev {
        enum subdev_type sdev_type;  // must be frist
        struct stfcamss *stfcamss;
-       atomic_t ref_count;
        u8 id;
        struct v4l2_subdev subdev;
        struct media_pad pads[STF_ISP_PADS_NUM];
        struct v4l2_mbus_framefmt fmt[STF_ISP_PADS_NUM];
-       struct v4l2_rect compose;
-       struct v4l2_rect crop;
-       const struct isp_format *formats;
+       struct isp_stream_format rect[ISP_RECT_MAX];
+       const struct isp_format_table *formats;
        unsigned int nformats;
        struct isp_hw_ops *hw_ops;
        struct mutex power_lock;
index 33c2696..1efc674 100644 (file)
@@ -303,10 +303,14 @@ static int stf_isp_config_set(struct stf_isp_dev *isp_dev)
 }
 
 static int stf_isp_set_format(struct stf_isp_dev *isp_dev,
-               struct v4l2_rect *crop, u32 mcode)
+               struct isp_stream_format *crop_array, u32 mcode,
+               int type)
                // u32 width, u32 height)
 {
        struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
+       struct stf_dvp_dev *dvp_dev = isp_dev->stfcamss->dvp_dev;
+       struct v4l2_rect *crop = &crop_array[ISP_COMPOSE].rect;
+       u32 bpp = crop_array[ISP_COMPOSE].bpp;
        void __iomem *ispbase;
        u32 val, val1;
 
@@ -320,6 +324,17 @@ static int stf_isp_set_format(struct stf_isp_dev *isp_dev,
                isp_settings = isp_sc2235_settings;
        }
 
+       st_debug(ST_ISP, "interface type is %d(%s)\n",
+                       type, type == CSI_SENSOR ? "CSI" : "DVP");
+
+       if (type == DVP_SENSOR) {
+               unsigned int flags = dvp_dev->dvp->flags;
+
+               st_debug(ST_ISP, "dvp flags = 0x%x, hsync active is %s, vsync active is %s\n",
+                       flags, flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH ? "high" : "low",
+                       flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH ? "high" : "low");
+       }
+
        val = crop->left + (crop->top << 16);
        isp_format_reg_list[0].addr = ISP_REG_PIC_CAPTURE_START_CFG;
        isp_format_reg_list[0].val = val;
@@ -334,7 +349,7 @@ static int stf_isp_set_format(struct stf_isp_dev *isp_dev,
        isp_format_reg_list[2].val = val;
 
        isp_format_reg_list[3].addr = ISP_REG_STRIDE;
-       isp_format_reg_list[3].val = crop->width;
+       isp_format_reg_list[3].val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_8);
 
        switch (mcode) {
        case MEDIA_BUS_FMT_SRGGB10_1X10:
@@ -367,6 +382,7 @@ static int stf_isp_set_format(struct stf_isp_dev *isp_dev,
                val1 = 0x10000000;
                break;
        }
+
        isp_format_reg_list[4].addr = ISP_REG_RAW_FORMAT_CFG;
        isp_format_reg_list[4].val = val;
 
@@ -374,14 +390,87 @@ static int stf_isp_set_format(struct stf_isp_dev *isp_dev,
        isp_format_reg_list[5].val = val1;
        isp_format_reg_list[5].mask = 0xF0000000;
 
-       st_info(ST_ISP, "left: %d, top: %d, width = %d, height = %d, code = 0x%x\n",
-               crop->left, crop->top, crop->width, crop->height, mcode);
+       st_info(ST_ISP, "src left: %d, top: %d, width = %d, height = %d, bpp = %d\n",
+               crop->left, crop->top, crop->width, crop->height, bpp);
+
+       crop = &crop_array[ISP_CROP].rect;
+       bpp = crop_array[ISP_CROP].bpp;
+       val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_128);
+       isp_format_reg_list[6].addr = ISP_REG_DUMP_CFG_1;
+       isp_format_reg_list[6].val = val | 3 << 16;
+       isp_format_reg_list[6].mask = 0x0003FFFF;
+
+       st_info(ST_ISP, "raw left: %d, top: %d, width = %d, height = %d, bpp = %d\n",
+               crop->left, crop->top, crop->width, crop->height, bpp);
+
+       crop = &crop_array[ISP_SCALE_SS0].rect;
+       bpp = crop_array[ISP_SCALE_SS0].bpp;
+       isp_format_reg_list[7].addr = ISP_REG_SS0IW;
+       isp_format_reg_list[7].val = (crop->width << 16) + crop->height;
+       isp_format_reg_list[8].addr = ISP_REG_SS0S;
+       isp_format_reg_list[8].val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_8);
+
+       st_info(ST_ISP, "ss0 left: %d, top: %d, width = %d, height = %d, bpp = %d\n",
+               crop->left, crop->top, crop->width, crop->height, bpp);
+
+       crop = &crop_array[ISP_SCALE_SS1].rect;
+       bpp = crop_array[ISP_SCALE_SS1].bpp;
+       isp_format_reg_list[9].addr = ISP_REG_SS1IW;
+       isp_format_reg_list[9].val = (crop->width << 16) + crop->height;
+       isp_format_reg_list[10].addr = ISP_REG_SS1S;
+       isp_format_reg_list[10].val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_8);
+
+       crop = &crop_array[ISP_ITIWS].rect;
+       bpp = crop_array[ISP_ITIWS].bpp;
+       isp_format_reg_list[11].addr = ISP_REG_ITIIWSR;
+       isp_format_reg_list[11].val = (crop->height << 16) + crop->width;
+       isp_format_reg_list[12].addr = ISP_REG_ITIDWLSR;
+       isp_format_reg_list[12].val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_8);
+       isp_format_reg_list[13].addr = ISP_REG_ITIDRLSR;
+       isp_format_reg_list[13].val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_8);
+
+       st_info(ST_ISP, "iti left: %d, top: %d, width = %d, height = %d, bpp = %d\n",
+               crop->left, crop->top, crop->width, crop->height, bpp);
+
+       isp_format_reg_list[14].addr = ISP_REG_SENSOR;
+       isp_format_reg_list[14].val = 0x00000000;
+       if (type == DVP_SENSOR) {
+               unsigned int flags = dvp_dev->dvp->flags;
+
+               if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
+                       isp_format_reg_list[14].val |= 0x08;
+               if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
+                       isp_format_reg_list[14].val |= 0x04;
+       } else {
+               isp_format_reg_list[14].val |= 0x01;
+       }
 
+       isp_load_regs(ispbase, isp_format_settings);
        return 0;
 }
 
 static int stf_isp_stream_set(struct stf_isp_dev *isp_dev, int on)
 {
+       struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
+
+       void __iomem *ispbase;
+
+       if (isp_dev->id == 0)
+               ispbase = vin->isp_isp0_base;
+       else
+               ispbase = vin->isp_isp1_base;
+
+       if (on) {
+#if defined(USE_NEW_CONFIG_SETTING)
+               isp_load_regs(ispbase, isp_reg_start_settings);
+#else
+               reg_set_bit(ispbase, ISP_REG_CSIINTS_ADDR, 0x3FFFF, 0x3000a);
+               reg_set_bit(ispbase, ISP_REG_IESHD_ADDR, BIT(1) | BIT(0), 0x3);
+               reg_set_bit(ispbase, ISP_REG_ISP_CTRL_0, BIT(0), 1);
+#endif //#if defined(USE_NEW_CONFIG_SETTING)
+       }
+       //else  //disable crash
+       //      reg_set_bit(ispbase, ISP_REG_ISP_CTRL_0, BIT(0), 0);
        return 0;
 }
 
index a165033..a21494e 100644 (file)
@@ -17,37 +17,41 @@ static const struct stfcamss_format_info formats_pix_st7110_wr[] = {
          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
        { MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_PIX_FMT_RGB565, 1,
          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+       { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1,
+         { { 1, 1 } }, { { 1, 1 } }, { 8 } },
+       { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1,
+         { { 1, 1 } }, { { 1, 1 } }, { 8 } },
+       { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1,
+         { { 1, 1 } }, { { 1, 1 } }, { 8 } },
+       { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1,
+         { { 1, 1 } }, { { 1, 1 } }, { 8 } },
+       { 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 } },
 };
 
 static const struct stfcamss_format_info formats_raw_st7110_isp[] = {
-       { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB12, 1,
+       { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12, 1,
          { { 1, 1 } }, { { 1, 1 } }, { 12 } },
-       { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG12, 1,
+       { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12, 1,
          { { 1, 1 } }, { { 1, 1 } }, { 12 } },
-       { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG12, 1,
+       { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12, 1,
          { { 1, 1 } }, { { 1, 1 } }, { 12 } },
-       { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR12, 1,
+       { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12, 1,
          { { 1, 1 } }, { { 1, 1 } }, { 12 } },
 };
 
 static const struct stfcamss_format_info formats_pix_st7110_isp[] = {
-       // { MEDIA_BUS_FMT_YUYV12_2X12, V4L2_PIX_FMT_NV21M, 2,
+       // { MEDIA_BUS_FMT_YUYV12_2X12, V4L2_PIX_FMT_NV12M, 2,
        //  { { 1, 1 }, { 1, 1 } }, { { 1, 1 }, { 1, 1 } }, { 8 , 4 } },
-       { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_NV21, 1,
-         { { 1, 1 } }, { { 2, 3 } }, { 8 } },
-       { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_NV21, 1,
-         { { 1, 1 } }, { { 2, 3 } }, { 8 } },
-       { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_NV21, 1,
-         { { 1, 1 } }, { { 2, 3 } }, { 8 } },
-       { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_NV21, 1,
-         { { 1, 1 } }, { { 2, 3 } }, { 8 } },
-       { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_NV12, 1,
-         { { 1, 1 } }, { { 2, 3 } }, { 8 } },
-       { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_NV12, 1,
-         { { 1, 1 } }, { { 2, 3 } }, { 8 } },
-       { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_NV12, 1,
+       { MEDIA_BUS_FMT_Y12_1X12, V4L2_PIX_FMT_NV12, 1,
          { { 1, 1 } }, { { 2, 3 } }, { 8 } },
-       { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_NV12, 1,
+       { MEDIA_BUS_FMT_Y12_1X12, V4L2_PIX_FMT_NV21, 1,
          { { 1, 1 } }, { { 2, 3 } }, { 8 } },
 };
 
@@ -136,10 +140,10 @@ static int __video_try_fmt(struct stfcamss_video *video,
                memset(pix_mp, 0, sizeof(*pix_mp));
 
                pix_mp->pixelformat = fi->pixelformat;
-               pix_mp->width = clamp_t(u32, width, 1,
+               pix_mp->width = clamp_t(u32, width, STFCAMSS_FRAME_MIN_WIDTH,
                                STFCAMSS_FRAME_MAX_WIDTH);
-               pix_mp->height = clamp_t(u32, height, 1,
-                               STFCAMSS_FRAME_MAX_HEIGHT_RDI);
+               pix_mp->height = clamp_t(u32, height, STFCAMSS_FRAME_MIN_HEIGHT,
+                               STFCAMSS_FRAME_MAX_HEIGHT);
                pix_mp->num_planes = fi->planes;
                for (j = 0; j < pix_mp->num_planes; j++) {
                        bpl = pix_mp->width / fi->hsub[j].numerator *
@@ -182,10 +186,10 @@ static int __video_try_fmt(struct stfcamss_video *video,
                memset(pix, 0, sizeof(*pix));
 
                pix->pixelformat = fi->pixelformat;
-               pix->width = clamp_t(u32, width, 1,
+               pix->width = clamp_t(u32, width, STFCAMSS_FRAME_MIN_WIDTH,
                                STFCAMSS_FRAME_MAX_WIDTH);
-               pix->height = clamp_t(u32, height, 1,
-                               STFCAMSS_FRAME_MAX_HEIGHT_RDI);
+               pix->height = clamp_t(u32, height, STFCAMSS_FRAME_MIN_HEIGHT,
+                               STFCAMSS_FRAME_MAX_HEIGHT);
                bpl = pix->width / fi->hsub[0].numerator *
                        fi->hsub[0].denominator * fi->bpp[0] / 8;
                bpl = ALIGN(bpl, video->bpl_alignment);
@@ -216,7 +220,7 @@ static int stf_video_init_format(struct stfcamss_video *video, int is_mp)
 {
        int ret;
        struct v4l2_format format = {
-               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               .type = video->type,
                .fmt.pix = {
                        .width = 1920,
                        .height = 1080,
@@ -224,24 +228,12 @@ static int stf_video_init_format(struct stfcamss_video *video, int is_mp)
                },
        };
 
-       struct v4l2_format format_mp = {
-               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
-               .fmt.pix = {
-                       .width = 1920,
-                       .height = 1080,
-                       .pixelformat = V4L2_PIX_FMT_NV21,
-               },
-       };
-
-       if (is_mp)
-               ret = __video_try_fmt(video, &format_mp, true);
-       else
-               ret = __video_try_fmt(video, &format, false);
+       ret = __video_try_fmt(video, &format, is_mp);
 
        if (ret < 0)
                return ret;
 
-       video->active_fmt = is_mp ? format_mp : format;
+       video->active_fmt = format;
 
        return 0;
 }
@@ -453,6 +445,9 @@ static struct v4l2_subdev *video_remote_subdev(
 static int video_get_subdev_format(struct stfcamss_video *video,
                struct v4l2_format *format)
 {
+       struct v4l2_pix_format *pix = &video->active_fmt.fmt.pix;
+       struct v4l2_pix_format_mplane *pix_mp =
+                               &video->active_fmt.fmt.pix_mp;
        struct v4l2_subdev_format fmt;
        struct v4l2_subdev *subdev;
        u32 pixelformat;
@@ -470,8 +465,10 @@ static int video_get_subdev_format(struct stfcamss_video *video,
        if (ret)
                return ret;
 
-       pixelformat = video->is_mp ? format->fmt.pix.pixelformat
-                               : format->fmt.pix_mp.pixelformat;
+       if (video->is_mp)
+               pixelformat = pix_mp->pixelformat;
+       else
+               pixelformat = pix->pixelformat;
        ret = video_find_format(fmt.format.code, pixelformat,
                                video->formats, video->nformats);
        if (ret < 0)
@@ -634,6 +631,50 @@ static const struct vb2_ops stf_video_vb2_q_ops = {
  * V4L2 ioctls
  */
 
+static int getcrop_pad_id(int video_id)
+{
+       int pad = 0;
+
+       switch (video_id) {
+       case VIN_LINE_WR:
+               pad = STF_VIN_PAD_SRC;
+               break;
+       case VIN_LINE_ISP0:
+       case VIN_LINE_ISP1:
+               pad = STF_ISP_PAD_SRC;
+               break;
+       case VIN_LINE_ISP0_SS0:
+       case VIN_LINE_ISP1_SS0:
+               pad = STF_ISP_PAD_SRC_SS0;
+               break;
+       case VIN_LINE_ISP0_SS1:
+       case VIN_LINE_ISP1_SS1:
+               pad = STF_ISP_PAD_SRC_SS1;
+               break;
+       case VIN_LINE_ISP0_ITIW:
+       case VIN_LINE_ISP1_ITIW:
+               pad = STF_ISP_PAD_SRC_ITIW;
+               break;
+       case VIN_LINE_ISP0_ITIR:
+       case VIN_LINE_ISP1_ITIR:
+               pad = STF_ISP_PAD_SRC_ITIR;
+               break;
+       case VIN_LINE_ISP0_RAW:
+       case VIN_LINE_ISP1_RAW:
+               pad = STF_ISP_PAD_SRC_RAW;
+               break;
+       case VIN_LINE_ISP0_SCD_Y:
+       case VIN_LINE_ISP1_SCD_Y:
+               pad = STF_ISP_PAD_SRC_SCD_Y;
+               break;
+       default:
+               pad = STF_ISP_PAD_SRC;
+               break;
+       }
+
+       return pad;
+}
+
 static int video_querycap(struct file *file, void *fh,
                        struct v4l2_capability *cap)
 {
@@ -790,7 +831,7 @@ static int video_enum_framesizes(struct file *file, void *fh,
                fsize->stepwise.min_width = STFCAMSS_FRAME_MIN_WIDTH;
                fsize->stepwise.max_width = STFCAMSS_FRAME_MAX_WIDTH;
                fsize->stepwise.min_height = STFCAMSS_FRAME_MIN_HEIGHT;
-               fsize->stepwise.max_height = STFCAMSS_FRAME_MAX_HEIGHT_PIX;
+               fsize->stepwise.max_height = STFCAMSS_FRAME_MAX_HEIGHT;
                fsize->stepwise.step_width = 1;
                fsize->stepwise.step_height = 1;
        }
@@ -858,6 +899,60 @@ static int video_g_fmt_mp(struct file *file, void *fh, struct v4l2_format *f)
        return 0;
 }
 
+static int video_entity_s_fmt(struct stfcamss_video *video,
+                       struct media_entity *entity,
+                       struct v4l2_subdev_state *state,
+                       struct v4l2_subdev_format *fmt, u32 dst_code)
+{
+       struct v4l2_subdev *subdev;
+       struct media_pad *pad;
+       struct v4l2_mbus_framefmt *mf = &fmt->format;
+       u32 width, height, code;
+       int ret, index = 0;
+       int padid = getcrop_pad_id(video->id);
+
+       code = mf->code;
+       width = mf->width;
+       height = mf->height;
+       subdev = media_entity_to_v4l2_subdev(entity);
+       while (1) {
+               if (index >= entity->num_pads)
+                       break;
+               if (index != 0 && !strncmp(subdev->name, "stf_isp", 7)
+                       && (index != padid) && (index != STF_ISP_PAD_SRC_RAW)) {
+                       index++;
+                       continue;
+               }
+               pad = &entity->pads[index];
+               pad = media_entity_remote_pad(pad);
+               if (pad && is_media_entity_v4l2_subdev(pad->entity)) {
+                       fmt->pad = index;
+                       if (index)
+                               mf->code = dst_code;
+                       ret = v4l2_subdev_call(subdev, pad, set_fmt, state, fmt);
+                       st_warn(ST_VIDEO,
+                               "\"%s\":%d pad fmt set to 0x%x %ux%u, dst_code = 0x%x\n",
+                               subdev->name, fmt->pad, mf->code,
+                               mf->width, mf->height, dst_code);
+                       if (mf->code != code ||
+                               mf->width != width || mf->height != height) {
+                               st_warn(ST_VIDEO,
+                                       "\"%s\":%d pad fmt has been"
+                                       " changed to 0x%x %ux%u\n",
+                                       subdev->name, fmt->pad, mf->code,
+                                       mf->width, mf->height);
+                       }
+                       if (index)
+                               ret = video_entity_s_fmt(video, pad->entity, state, fmt, dst_code);
+               }
+
+               if (ret < 0 && ret != -ENOIOCTLCMD)
+                       break;
+               index++;
+       }
+       return ret;
+}
+
 static int video_pipeline_s_fmt(struct stfcamss_video *video,
                        struct v4l2_subdev_state *state,
                        struct v4l2_format *f)
@@ -865,16 +960,17 @@ static int video_pipeline_s_fmt(struct stfcamss_video *video,
        struct video_device *vdev = &video->vdev;
        struct media_entity *entity = &vdev->entity;
        struct v4l2_subdev *subdev;
-       struct media_device *mdev = entity->graph_obj.mdev;
-       struct media_graph graph;
        int ret, index;
        struct v4l2_subdev_format fmt = {
                .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+               .reserved = {getcrop_pad_id(video->id)}
        };
        struct v4l2_mbus_framefmt *mf = &fmt.format;
        struct v4l2_pix_format *pix = &f->fmt.pix;
        struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+       struct media_entity *sensor;
        u32 width, height, code;
+       struct media_pad *pad;
 
        /* pix to mbus format */
        if (video->is_mp) {
@@ -885,9 +981,6 @@ static int video_pipeline_s_fmt(struct stfcamss_video *video,
                        return index;
                v4l2_fill_mbus_format_mplane(mf, pix_mp);
                mf->code = video->formats[index].code;
-               code = mf->code;
-               width = mf->width;
-               height = mf->height;
        } else {
                index = video_find_format(mf->code,
                                        pix->pixelformat,
@@ -895,53 +988,48 @@ static int video_pipeline_s_fmt(struct stfcamss_video *video,
                if (index < 0)
                        return index;
                v4l2_fill_mbus_format(mf, pix, video->formats[index].code);
-               code = mf->code;
-               width = mf->width;
-               height = mf->height;
+       }
+       code = mf->code;
+       width = mf->width;
+       height = mf->height;
+       sensor = stfcamss_find_sensor(entity);
+       if (sensor) {
+               subdev = media_entity_to_v4l2_subdev(sensor);
+               ret = v4l2_subdev_call(subdev, pad, set_fmt, state, &fmt);
+               st_warn(ST_VIDEO,
+                       "\"%s\":%d pad fmt set to 0x%x %ux%u\n",
+                       subdev->name, fmt.pad, mf->code,
+                       mf->width, mf->height);
+               if (mf->code != code ||
+                       mf->width != width || mf->height != height) {
+                       st_warn(ST_VIDEO,
+                               "\"%s\":%d pad fmt has been"
+                               " changed to 0x%x %ux%u\n",
+                               subdev->name, fmt.pad, mf->code,
+                               mf->width, mf->height);
+               }
+       } else {
+               st_err(ST_VIDEO, "Can't find sensor\n");
+               return -EINVAL;
        }
        /*
         * Starting from sensor subdevice, walk within
         * pipeline and set format on each subdevice
         */
-       mutex_lock(&mdev->graph_mutex);
-       ret = media_graph_walk_init(&graph, mdev);
-       if (ret) {
-               mutex_unlock(&mdev->graph_mutex);
-               return ret;
-       }
-
-       media_graph_walk_start(&graph, entity);
-
-       while (!ret && (entity = media_graph_walk_next(&graph)))
-               if (is_media_entity_v4l2_subdev(entity)) {
-                       subdev = media_entity_to_v4l2_subdev(entity);
-                       ret = v4l2_subdev_call(subdev, pad, set_fmt, state, &fmt);
-                       if (ret < 0 && ret != -ENOIOCTLCMD)
-                               break;
-                       if (mf->code != code ||
-                           mf->width != width || mf->height != height) {
-                               // st_warn(ST_VIDEO,
-                               //      "\"%s\":%d pad fmt has been"
-                               //      " changed to 0x%x %ux%u\n",
-                               //      subdev->name, fmt.pad, mf->code,
-                               //      mf->width, mf->height);
-                       }
-               }
-
-       mutex_unlock(&mdev->graph_mutex);
-
-       media_graph_walk_cleanup(&graph);
+       sensor = stfcamss_find_sensor(entity);
+       pad = media_entity_remote_pad(&sensor->pads[0]);
+       ret = video_entity_s_fmt(video, pad->entity, state, &fmt, code);
 
        if (ret < 0 && ret != -ENOIOCTLCMD) {
-               // st_err(ST_VIDEO,
-               //      "%s: Failed to set fmt 0x%x %ux%u"
-               //      " on \"%s\":%d pad (%d)\n",
-               //      __func__, mf->code,
-               //      mf->width, mf->height,
-               //      subdev->name, fmt.pad, ret);
                return ret;
        }
 
+       index = video_find_format(mf->code,
+                               video->formats[index].pixelformat,
+                               video->formats, video->nformats);
+       if (index < 0)
+               return index;
+
        if (video->is_mp)
                video_mbus_to_pix_mp(mf, pix_mp,
                                &video->formats[index], video->bpl_alignment);
@@ -1128,6 +1216,7 @@ int video_g_selection(struct file *file, void *fh,
        struct media_pad *pad;
        struct v4l2_subdev_selection sel = {
                .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+               .pad = getcrop_pad_id(video->id),
                .target = s->target,
                .r = s->r,
                .flags = s->flags,
@@ -1176,6 +1265,7 @@ int video_s_selection(struct file *file, void *fh,
        struct media_pad *pad;
        struct v4l2_subdev_selection sel = {
                .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+               .pad = getcrop_pad_id(video->id),
                .target = s->target,
                .r = s->r,
                .flags = s->flags,
index 896124a..d1b8e4d 100755 (executable)
@@ -16,8 +16,7 @@
 #define STFCAMSS_FRAME_MIN_WIDTH           64
 #define STFCAMSS_FRAME_MAX_WIDTH           8191
 #define STFCAMSS_FRAME_MIN_HEIGHT          64
-#define STFCAMSS_FRAME_MAX_HEIGHT_RDI      8191
-#define STFCAMSS_FRAME_MAX_HEIGHT_PIX      4096
+#define STFCAMSS_FRAME_MAX_HEIGHT          8191
 #define STFCAMSS_FRAME_WIDTH_ALIGN_8       8
 #define STFCAMSS_FRAME_WIDTH_ALIGN_128     128
 #define STFCAMSS_MIN_BUFFERS               2
index af1348c..7b686d8 100644 (file)
 static const struct vin2_format vin2_formats_st7110[] = {
        { MEDIA_BUS_FMT_YUYV8_2X8, 16},
        { MEDIA_BUS_FMT_RGB565_2X8_LE, 16},
-       { MEDIA_BUS_FMT_SRGGB10_1X10, 12},
-       { MEDIA_BUS_FMT_SGRBG10_1X10, 12},
-       { MEDIA_BUS_FMT_SGBRG10_1X10, 12},
-       { MEDIA_BUS_FMT_SBGGR10_1X10, 12},
+       { MEDIA_BUS_FMT_SRGGB8_1X8, 8},
+       { MEDIA_BUS_FMT_SGRBG8_1X8, 8},
+       { MEDIA_BUS_FMT_SGBRG8_1X8, 8},
+       { MEDIA_BUS_FMT_SBGGR8_1X8, 8},
+       { MEDIA_BUS_FMT_SRGGB10_1X10, 10},
+       { MEDIA_BUS_FMT_SGRBG10_1X10, 10},
+       { MEDIA_BUS_FMT_SGBRG10_1X10, 10},
+       { MEDIA_BUS_FMT_SBGGR10_1X10, 10},
+       { MEDIA_BUS_FMT_SRGGB12_1X12, 12},
+       { MEDIA_BUS_FMT_SGRBG12_1X12, 12},
+       { MEDIA_BUS_FMT_SGBRG12_1X12, 12},
+       { MEDIA_BUS_FMT_SBGGR12_1X12, 12},
+       { MEDIA_BUS_FMT_Y12_1X12, 8},
+       { MEDIA_BUS_FMT_YUV8_1X24, 8},
+};
+
+static const struct vin2_format isp_formats_st7110_raw[] = {
+       { MEDIA_BUS_FMT_SRGGB12_1X12, 12},
+       { MEDIA_BUS_FMT_SGRBG12_1X12, 12},
+       { MEDIA_BUS_FMT_SGBRG12_1X12, 12},
+       { MEDIA_BUS_FMT_SBGGR12_1X12, 12},
+};
+
+static const struct vin2_format isp_formats_st7110_uo[] = {
+       { MEDIA_BUS_FMT_Y12_1X12, 8},
+};
+
+static const struct vin2_format isp_formats_st7110_iti[] = {
+       { MEDIA_BUS_FMT_SRGGB10_1X10, 10},
+       { MEDIA_BUS_FMT_SGRBG10_1X10, 10},
+       { MEDIA_BUS_FMT_SGBRG10_1X10, 10},
+       { MEDIA_BUS_FMT_SBGGR10_1X10, 10},
+       { MEDIA_BUS_FMT_SRGGB12_1X12, 12},
+       { MEDIA_BUS_FMT_SGRBG12_1X12, 12},
+       { MEDIA_BUS_FMT_SGBRG12_1X12, 12},
+       { MEDIA_BUS_FMT_SBGGR12_1X12, 12},
+       { MEDIA_BUS_FMT_Y12_1X12, 8},
+       { MEDIA_BUS_FMT_YUV8_1X24, 8},
+};
+
+static const struct vin2_format_table vin2_formats_table[] = {
+       { vin2_formats_st7110, ARRAY_SIZE(vin2_formats_st7110) },         // VIN_LINE_WR
+       { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) },     // VIN_LINE_ISP0
+       { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) },     // VIN_LINE_ISP1
+       { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) },     // VIN_LINE_ISP0_SS0
+       { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) },     // VIN_LINE_ISP1_SS0
+       { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) },     // VIN_LINE_ISP0_SS1
+       { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) },     // VIN_LINE_ISP1_SS1
+       { isp_formats_st7110_iti, ARRAY_SIZE(isp_formats_st7110_iti) },   // VIN_LINE_ISP0_ITIW
+       { isp_formats_st7110_iti, ARRAY_SIZE(isp_formats_st7110_iti) },   // VIN_LINE_ISP1_ITIW
+       { isp_formats_st7110_iti, ARRAY_SIZE(isp_formats_st7110_iti) },   // VIN_LINE_ISP0_ITIR
+       { isp_formats_st7110_iti, ARRAY_SIZE(isp_formats_st7110_iti) },   // VIN_LINE_ISP1_ITIR
+       { isp_formats_st7110_raw, ARRAY_SIZE(isp_formats_st7110_raw) },   // VIN_LINE_ISP0_RAW
+       { isp_formats_st7110_raw, ARRAY_SIZE(isp_formats_st7110_raw) },   // VIN_LINE_ISP1_RAW
+       { isp_formats_st7110_raw, ARRAY_SIZE(isp_formats_st7110_raw) },   // VIN_LINE_ISP0_SCD_Y
+       { isp_formats_st7110_raw, ARRAY_SIZE(isp_formats_st7110_raw) },   // VIN_LINE_ISP1_SCD_Y
 };
 
 static void vin_buffer_done(struct vin_line *line, struct vin_params *params);
@@ -238,8 +290,8 @@ int stf_vin_subdev_init(struct stfcamss *stfcamss)
                l->video_out.stfcamss = stfcamss;
                l->id = i;
                l->sdev_type = VIN_DEV_TYPE;
-               l->formats = vin2_formats_st7110;
-               l->nformats = ARRAY_SIZE(vin2_formats_st7110);
+               l->formats = vin2_formats_table[i].fmts;
+               l->nformats = vin2_formats_table[i].nfmts;
                spin_lock_init(&l->output_lock);
 
                mutex_init(&l->stream_lock);
@@ -721,12 +773,12 @@ static void vin_try_format(struct vin_line *line,
 
                /* If not found, use UYVY as default */
                if (i >= line->nformats)
-                       fmt->code = MEDIA_BUS_FMT_RGB565_2X8_LE;
+                       fmt->code = line->formats[0].code;
 
                fmt->width = clamp_t(u32,
-                               fmt->width, 1, STFCAMSS_FRAME_MAX_WIDTH);
+                               fmt->width, STFCAMSS_FRAME_MIN_WIDTH, STFCAMSS_FRAME_MAX_WIDTH);
                fmt->height = clamp_t(u32,
-                               fmt->height, 1, STFCAMSS_FRAME_MAX_HEIGHT_PIX);
+                               fmt->height, STFCAMSS_FRAME_MIN_HEIGHT, STFCAMSS_FRAME_MAX_HEIGHT);
 
                fmt->field = V4L2_FIELD_NONE;
                fmt->colorspace = V4L2_COLORSPACE_SRGB;
index 02b6518..e463dae 100755 (executable)
@@ -24,6 +24,11 @@ struct vin2_format {
        u8 bpp;
 };
 
+struct vin2_format_table {
+       const struct vin2_format *fmts;
+       int nfmts;
+};
+
 enum vin_output_state {
        VIN_OUTPUT_OFF,
        VIN_OUTPUT_RESERVED,