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;
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;
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;
#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)
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;
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;
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;
}
}
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;
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;
}
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)
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);
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,
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);
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;
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;
}
{
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;
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;
}
u8 bpp;
};
+struct isp_format_table {
+ const struct isp_format *fmts;
+ int nfmts;
+};
+
struct regval_t {
u32 addr;
u32 val;
int regval_num;
};
+struct isp_stream_format {
+ struct v4l2_rect rect;
+ u32 bpp;
+};
+
struct stf_isp_dev;
enum subdev_type;
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);
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;
}
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;
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;
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:
val1 = 0x10000000;
break;
}
+
isp_format_reg_list[4].addr = ISP_REG_RAW_FORMAT_CFG;
isp_format_reg_list[4].val = val;
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;
}
{ { 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 } },
};
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 *
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);
{
int ret;
struct v4l2_format format = {
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .type = video->type,
.fmt.pix = {
.width = 1920,
.height = 1080,
},
};
- 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;
}
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;
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)
* 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)
{
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;
}
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)
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) {
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,
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);
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,
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,
#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
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);
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);
/* 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;
u8 bpp;
};
+struct vin2_format_table {
+ const struct vin2_format *fmts;
+ int nfmts;
+};
+
enum vin_output_state {
VIN_OUTPUT_OFF,
VIN_OUTPUT_RESERVED,