1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * vimc-common.c Virtual Media Controller Driver
5 * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
8 #include <linux/init.h>
9 #include <linux/module.h>
11 #include "vimc-common.h"
14 * NOTE: non-bayer formats need to come first (necessary for enum_mbus_code
17 static const struct vimc_pix_map vimc_pix_map_list
[] = {
18 /* TODO: add all missing formats */
22 .code
= MEDIA_BUS_FMT_BGR888_1X24
,
23 .pixelformat
= V4L2_PIX_FMT_BGR24
,
28 .code
= MEDIA_BUS_FMT_RGB888_1X24
,
29 .pixelformat
= V4L2_PIX_FMT_RGB24
,
34 .code
= MEDIA_BUS_FMT_ARGB8888_1X32
,
35 .pixelformat
= V4L2_PIX_FMT_ARGB32
,
42 .code
= MEDIA_BUS_FMT_SBGGR8_1X8
,
43 .pixelformat
= V4L2_PIX_FMT_SBGGR8
,
48 .code
= MEDIA_BUS_FMT_SGBRG8_1X8
,
49 .pixelformat
= V4L2_PIX_FMT_SGBRG8
,
54 .code
= MEDIA_BUS_FMT_SGRBG8_1X8
,
55 .pixelformat
= V4L2_PIX_FMT_SGRBG8
,
60 .code
= MEDIA_BUS_FMT_SRGGB8_1X8
,
61 .pixelformat
= V4L2_PIX_FMT_SRGGB8
,
66 .code
= MEDIA_BUS_FMT_SBGGR10_1X10
,
67 .pixelformat
= V4L2_PIX_FMT_SBGGR10
,
72 .code
= MEDIA_BUS_FMT_SGBRG10_1X10
,
73 .pixelformat
= V4L2_PIX_FMT_SGBRG10
,
78 .code
= MEDIA_BUS_FMT_SGRBG10_1X10
,
79 .pixelformat
= V4L2_PIX_FMT_SGRBG10
,
84 .code
= MEDIA_BUS_FMT_SRGGB10_1X10
,
85 .pixelformat
= V4L2_PIX_FMT_SRGGB10
,
90 /* 10bit raw bayer a-law compressed to 8 bits */
92 .code
= MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8
,
93 .pixelformat
= V4L2_PIX_FMT_SBGGR10ALAW8
,
98 .code
= MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8
,
99 .pixelformat
= V4L2_PIX_FMT_SGBRG10ALAW8
,
104 .code
= MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8
,
105 .pixelformat
= V4L2_PIX_FMT_SGRBG10ALAW8
,
110 .code
= MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8
,
111 .pixelformat
= V4L2_PIX_FMT_SRGGB10ALAW8
,
116 /* 10bit raw bayer DPCM compressed to 8 bits */
118 .code
= MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8
,
119 .pixelformat
= V4L2_PIX_FMT_SBGGR10DPCM8
,
124 .code
= MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8
,
125 .pixelformat
= V4L2_PIX_FMT_SGBRG10DPCM8
,
130 .code
= MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8
,
131 .pixelformat
= V4L2_PIX_FMT_SGRBG10DPCM8
,
136 .code
= MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8
,
137 .pixelformat
= V4L2_PIX_FMT_SRGGB10DPCM8
,
142 .code
= MEDIA_BUS_FMT_SBGGR12_1X12
,
143 .pixelformat
= V4L2_PIX_FMT_SBGGR12
,
148 .code
= MEDIA_BUS_FMT_SGBRG12_1X12
,
149 .pixelformat
= V4L2_PIX_FMT_SGBRG12
,
154 .code
= MEDIA_BUS_FMT_SGRBG12_1X12
,
155 .pixelformat
= V4L2_PIX_FMT_SGRBG12
,
160 .code
= MEDIA_BUS_FMT_SRGGB12_1X12
,
161 .pixelformat
= V4L2_PIX_FMT_SRGGB12
,
167 bool vimc_is_source(struct media_entity
*ent
)
171 for (i
= 0; i
< ent
->num_pads
; i
++)
172 if (ent
->pads
[i
].flags
& MEDIA_PAD_FL_SINK
)
177 const struct vimc_pix_map
*vimc_pix_map_by_index(unsigned int i
)
179 if (i
>= ARRAY_SIZE(vimc_pix_map_list
))
182 return &vimc_pix_map_list
[i
];
185 const struct vimc_pix_map
*vimc_pix_map_by_code(u32 code
)
189 for (i
= 0; i
< ARRAY_SIZE(vimc_pix_map_list
); i
++) {
190 if (vimc_pix_map_list
[i
].code
== code
)
191 return &vimc_pix_map_list
[i
];
196 const struct vimc_pix_map
*vimc_pix_map_by_pixelformat(u32 pixelformat
)
200 for (i
= 0; i
< ARRAY_SIZE(vimc_pix_map_list
); i
++) {
201 if (vimc_pix_map_list
[i
].pixelformat
== pixelformat
)
202 return &vimc_pix_map_list
[i
];
207 static int vimc_get_pix_format(struct media_pad
*pad
,
208 struct v4l2_pix_format
*fmt
)
210 if (is_media_entity_v4l2_subdev(pad
->entity
)) {
211 struct v4l2_subdev
*sd
=
212 media_entity_to_v4l2_subdev(pad
->entity
);
213 struct v4l2_subdev_format sd_fmt
;
214 const struct vimc_pix_map
*pix_map
;
217 sd_fmt
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
218 sd_fmt
.pad
= pad
->index
;
220 ret
= v4l2_subdev_call(sd
, pad
, get_fmt
, NULL
, &sd_fmt
);
224 v4l2_fill_pix_format(fmt
, &sd_fmt
.format
);
225 pix_map
= vimc_pix_map_by_code(sd_fmt
.format
.code
);
226 fmt
->pixelformat
= pix_map
->pixelformat
;
227 } else if (is_media_entity_v4l2_video_device(pad
->entity
)) {
228 struct video_device
*vdev
= container_of(pad
->entity
,
231 struct vimc_ent_device
*ved
= video_get_drvdata(vdev
);
233 if (!ved
->vdev_get_format
)
236 ved
->vdev_get_format(ved
, fmt
);
244 int vimc_vdev_link_validate(struct media_link
*link
)
246 struct v4l2_pix_format source_fmt
, sink_fmt
;
249 ret
= vimc_get_pix_format(link
->source
, &source_fmt
);
253 ret
= vimc_get_pix_format(link
->sink
, &sink_fmt
);
257 pr_info("vimc link validate: "
258 "%s:src:%dx%d (0x%x, %d, %d, %d, %d) "
259 "%s:snk:%dx%d (0x%x, %d, %d, %d, %d)\n",
261 link
->source
->entity
->name
,
262 source_fmt
.width
, source_fmt
.height
,
263 source_fmt
.pixelformat
, source_fmt
.colorspace
,
264 source_fmt
.quantization
, source_fmt
.xfer_func
,
265 source_fmt
.ycbcr_enc
,
267 link
->sink
->entity
->name
,
268 sink_fmt
.width
, sink_fmt
.height
,
269 sink_fmt
.pixelformat
, sink_fmt
.colorspace
,
270 sink_fmt
.quantization
, sink_fmt
.xfer_func
,
273 /* The width, height and pixelformat must match. */
274 if (source_fmt
.width
!= sink_fmt
.width
||
275 source_fmt
.height
!= sink_fmt
.height
||
276 source_fmt
.pixelformat
!= sink_fmt
.pixelformat
)
280 * The field order must match, or the sink field order must be NONE
281 * to support interlaced hardware connected to bridges that support
282 * progressive formats only.
284 if (source_fmt
.field
!= sink_fmt
.field
&&
285 sink_fmt
.field
!= V4L2_FIELD_NONE
)
289 * If colorspace is DEFAULT, then assume all the colorimetry is also
290 * DEFAULT, return 0 to skip comparing the other colorimetry parameters
292 if (source_fmt
.colorspace
== V4L2_COLORSPACE_DEFAULT
||
293 sink_fmt
.colorspace
== V4L2_COLORSPACE_DEFAULT
)
296 /* Colorspace must match. */
297 if (source_fmt
.colorspace
!= sink_fmt
.colorspace
)
300 /* Colorimetry must match if they are not set to DEFAULT */
301 if (source_fmt
.ycbcr_enc
!= V4L2_YCBCR_ENC_DEFAULT
&&
302 sink_fmt
.ycbcr_enc
!= V4L2_YCBCR_ENC_DEFAULT
&&
303 source_fmt
.ycbcr_enc
!= sink_fmt
.ycbcr_enc
)
306 if (source_fmt
.quantization
!= V4L2_QUANTIZATION_DEFAULT
&&
307 sink_fmt
.quantization
!= V4L2_QUANTIZATION_DEFAULT
&&
308 source_fmt
.quantization
!= sink_fmt
.quantization
)
311 if (source_fmt
.xfer_func
!= V4L2_XFER_FUNC_DEFAULT
&&
312 sink_fmt
.xfer_func
!= V4L2_XFER_FUNC_DEFAULT
&&
313 source_fmt
.xfer_func
!= sink_fmt
.xfer_func
)
319 static const struct media_entity_operations vimc_ent_sd_mops
= {
320 .link_validate
= v4l2_subdev_link_validate
,
323 int vimc_ent_sd_register(struct vimc_ent_device
*ved
,
324 struct v4l2_subdev
*sd
,
325 struct v4l2_device
*v4l2_dev
,
326 const char *const name
,
329 struct media_pad
*pads
,
330 const struct v4l2_subdev_ops
*sd_ops
)
334 /* Fill the vimc_ent_device struct */
335 ved
->ent
= &sd
->entity
;
337 /* Initialize the subdev */
338 v4l2_subdev_init(sd
, sd_ops
);
339 sd
->entity
.function
= function
;
340 sd
->entity
.ops
= &vimc_ent_sd_mops
;
341 sd
->owner
= THIS_MODULE
;
342 strscpy(sd
->name
, name
, sizeof(sd
->name
));
343 v4l2_set_subdevdata(sd
, ved
);
345 /* Expose this subdev to user space */
346 sd
->flags
|= V4L2_SUBDEV_FL_HAS_DEVNODE
;
347 if (sd
->ctrl_handler
)
348 sd
->flags
|= V4L2_SUBDEV_FL_HAS_EVENTS
;
350 /* Initialize the media entity */
351 ret
= media_entity_pads_init(&sd
->entity
, num_pads
, pads
);
355 /* Register the subdev with the v4l2 and the media framework */
356 ret
= v4l2_device_register_subdev(v4l2_dev
, sd
);
358 dev_err(v4l2_dev
->dev
,
359 "%s: subdev register failed (err=%d)\n",
361 goto err_clean_m_ent
;
367 media_entity_cleanup(&sd
->entity
);