summaryrefslogtreecommitdiff
path: root/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
diff options
context:
space:
mode:
authorPaul Kocialkowski <paul.kocialkowski@bootlin.com>2022-11-03 19:31:03 +0300
committerMauro Carvalho Chehab <mchehab@kernel.org>2022-11-25 10:14:01 +0300
commit1fd07a8040f9fb1d34fe790d72cb1e275e558ef4 (patch)
tree0c9857c65f7cecb4f36cd49d9d7c03e508d314eb /drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
parent9ff5d37cebb0698627b959d032e86d49f80f0de1 (diff)
downloadlinux-1fd07a8040f9fb1d34fe790d72cb1e275e558ef4.tar.xz
media: sun6i-csi: Implement capture link validation with logic
Rework the capture link validate implementation with actual logic that reflects the possibilities of the device instead of the combinatory helper functions, using the added match list helper sun6i_csi_is_format_supported() when needed. Remove the previous dedicated helper. Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com> Acked-by: Jernej Skrabec <jernej.skrabec@gmail.com> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
Diffstat (limited to 'drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c')
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c223
1 files changed, 179 insertions, 44 deletions
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
index 75984bfa4576..239875f2b530 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
@@ -227,6 +227,123 @@ struct sun6i_csi_capture_format *sun6i_csi_capture_format_find(u32 pixelformat)
return NULL;
}
+/* RAW formats need an exact match between pixel and mbus formats. */
+static const
+struct sun6i_csi_capture_format_match sun6i_csi_capture_format_matches[] = {
+ /* YUV420 */
+ {
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_YVYU,
+ .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_YVYU,
+ .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_VYUY,
+ .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_VYUY,
+ .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16,
+ },
+ /* RGB */
+ {
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_RGB565X,
+ .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_BE,
+ },
+ /* Bayer */
+ {
+ .pixelformat = V4L2_PIX_FMT_SBGGR8,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SGBRG8,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SGRBG8,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SRGGB8,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SBGGR10,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SGBRG10,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SGRBG10,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SRGGB10,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SBGGR12,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SGBRG12,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SGRBG12,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SRGGB12,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ },
+ /* Compressed */
+ {
+ .pixelformat = V4L2_PIX_FMT_JPEG,
+ .mbus_code = MEDIA_BUS_FMT_JPEG_1X8,
+ },
+};
+
+static bool sun6i_csi_capture_format_match(u32 pixelformat, u32 mbus_code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(sun6i_csi_capture_format_matches); i++) {
+ const struct sun6i_csi_capture_format_match *match =
+ &sun6i_csi_capture_format_matches[i];
+
+ if (match->pixelformat == pixelformat &&
+ match->mbus_code == mbus_code)
+ return true;
+ }
+
+ return false;
+}
+
/* Capture */
static void sun6i_csi_capture_irq_enable(struct sun6i_csi_device *csi_dev)
@@ -1019,63 +1136,81 @@ static const struct v4l2_file_operations sun6i_csi_capture_fops = {
/* Media Entity */
-static int
-sun6i_csi_capture_link_validate_get_format(struct media_pad *pad,
- struct v4l2_subdev_format *fmt)
+static int sun6i_csi_capture_link_validate(struct media_link *link)
{
- if (is_media_entity_v4l2_subdev(pad->entity)) {
- struct v4l2_subdev *sd =
- media_entity_to_v4l2_subdev(pad->entity);
+ struct video_device *video_dev =
+ media_entity_to_video_device(link->sink->entity);
+ struct sun6i_csi_device *csi_dev = video_get_drvdata(video_dev);
+ struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev;
+ const struct sun6i_csi_capture_format *capture_format;
+ const struct sun6i_csi_bridge_format *bridge_format;
+ unsigned int capture_width, capture_height;
+ unsigned int bridge_width, bridge_height;
+ const struct v4l2_format_info *format_info;
+ u32 pixelformat, capture_field;
+ u32 mbus_code, bridge_field;
+ bool match;
- fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
- fmt->pad = pad->index;
- return v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt);
- }
+ sun6i_csi_capture_dimensions(csi_dev, &capture_width, &capture_height);
- return -EINVAL;
-}
+ sun6i_csi_capture_format(csi_dev, &pixelformat, &capture_field);
+ capture_format = sun6i_csi_capture_format_find(pixelformat);
+ if (WARN_ON(!capture_format))
+ return -EINVAL;
-static int sun6i_csi_capture_link_validate(struct media_link *link)
-{
- struct video_device *vdev = container_of(link->sink->entity,
- struct video_device, entity);
- struct sun6i_csi_device *csi_dev = video_get_drvdata(vdev);
- struct sun6i_csi_capture *capture = &csi_dev->capture;
- struct v4l2_subdev_format source_fmt;
- int ret;
+ sun6i_csi_bridge_dimensions(csi_dev, &bridge_width, &bridge_height);
- if (!media_pad_remote_pad_first(link->sink->entity->pads)) {
- dev_info(csi_dev->dev, "capture node %s pad not connected\n",
- vdev->name);
- return -ENOLINK;
+ sun6i_csi_bridge_format(csi_dev, &mbus_code, &bridge_field);
+ bridge_format = sun6i_csi_bridge_format_find(mbus_code);
+ if (WARN_ON(!bridge_format))
+ return -EINVAL;
+
+ /* No cropping/scaling is supported. */
+ if (capture_width != bridge_width || capture_height != bridge_height) {
+ v4l2_err(v4l2_dev,
+ "invalid input/output dimensions: %ux%u/%ux%u\n",
+ bridge_width, bridge_height, capture_width,
+ capture_height);
+ return -EINVAL;
}
- ret = sun6i_csi_capture_link_validate_get_format(link->source,
- &source_fmt);
- if (ret < 0)
- return ret;
+ format_info = v4l2_format_info(pixelformat);
+ /* Some formats are not listed. */
+ if (!format_info)
+ return 0;
- if (!sun6i_csi_is_format_supported(csi_dev,
- capture->format.fmt.pix.pixelformat,
- source_fmt.format.code)) {
- dev_err(csi_dev->dev,
- "Unsupported pixformat: 0x%x with mbus code: 0x%x!\n",
- capture->format.fmt.pix.pixelformat,
- source_fmt.format.code);
- return -EPIPE;
+ if (format_info->pixel_enc == V4L2_PIXEL_ENC_BAYER &&
+ bridge_format->input_format != SUN6I_CSI_INPUT_FMT_RAW)
+ goto invalid;
+
+ if (format_info->pixel_enc == V4L2_PIXEL_ENC_RGB &&
+ bridge_format->input_format != SUN6I_CSI_INPUT_FMT_RAW)
+ goto invalid;
+
+ if (format_info->pixel_enc == V4L2_PIXEL_ENC_YUV) {
+ if (bridge_format->input_format != SUN6I_CSI_INPUT_FMT_YUV420 &&
+ bridge_format->input_format != SUN6I_CSI_INPUT_FMT_YUV422)
+ goto invalid;
+
+ /* YUV420 input can't produce YUV422 output. */
+ if (bridge_format->input_format == SUN6I_CSI_INPUT_FMT_YUV420 &&
+ format_info->vdiv == 1)
+ goto invalid;
}
- if (source_fmt.format.width != capture->format.fmt.pix.width ||
- source_fmt.format.height != capture->format.fmt.pix.height) {
- dev_err(csi_dev->dev,
- "Wrong width or height %ux%u (%ux%u expected)\n",
- capture->format.fmt.pix.width,
- capture->format.fmt.pix.height,
- source_fmt.format.width, source_fmt.format.height);
- return -EPIPE;
+ /* With raw input mode, we need a 1:1 match between input and output. */
+ if (bridge_format->input_format == SUN6I_CSI_INPUT_FMT_RAW ||
+ capture_format->input_format_raw) {
+ match = sun6i_csi_capture_format_match(pixelformat, mbus_code);
+ if (!match)
+ goto invalid;
}
return 0;
+
+invalid:
+ v4l2_err(v4l2_dev, "invalid input/output format combination\n");
+ return -EINVAL;
}
static const struct media_entity_operations sun6i_csi_capture_media_ops = {