diff options
Diffstat (limited to 'drivers/media/platform/vimc/vimc-common.c')
-rw-r--r-- | drivers/media/platform/vimc/vimc-common.c | 121 |
1 files changed, 120 insertions, 1 deletions
diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c index f809a9d756b9..6ad77fdc04ad 100644 --- a/drivers/media/platform/vimc/vimc-common.c +++ b/drivers/media/platform/vimc/vimc-common.c | |||
@@ -252,8 +252,127 @@ int vimc_pipeline_s_stream(struct media_entity *ent, int enable) | |||
252 | return 0; | 252 | return 0; |
253 | } | 253 | } |
254 | 254 | ||
255 | static int vimc_get_mbus_format(struct media_pad *pad, | ||
256 | struct v4l2_subdev_format *fmt) | ||
257 | { | ||
258 | if (is_media_entity_v4l2_subdev(pad->entity)) { | ||
259 | struct v4l2_subdev *sd = | ||
260 | media_entity_to_v4l2_subdev(pad->entity); | ||
261 | int ret; | ||
262 | |||
263 | fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE; | ||
264 | fmt->pad = pad->index; | ||
265 | |||
266 | ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt); | ||
267 | if (ret) | ||
268 | return ret; | ||
269 | |||
270 | } else if (is_media_entity_v4l2_video_device(pad->entity)) { | ||
271 | struct video_device *vdev = container_of(pad->entity, | ||
272 | struct video_device, | ||
273 | entity); | ||
274 | struct vimc_ent_device *ved = video_get_drvdata(vdev); | ||
275 | const struct vimc_pix_map *vpix; | ||
276 | struct v4l2_pix_format vdev_fmt; | ||
277 | |||
278 | if (!ved->vdev_get_format) | ||
279 | return -ENOIOCTLCMD; | ||
280 | |||
281 | ved->vdev_get_format(ved, &vdev_fmt); | ||
282 | vpix = vimc_pix_map_by_pixelformat(vdev_fmt.pixelformat); | ||
283 | v4l2_fill_mbus_format(&fmt->format, &vdev_fmt, vpix->code); | ||
284 | } else { | ||
285 | return -EINVAL; | ||
286 | } | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | int vimc_link_validate(struct media_link *link) | ||
292 | { | ||
293 | struct v4l2_subdev_format source_fmt, sink_fmt; | ||
294 | int ret; | ||
295 | |||
296 | /* | ||
297 | * if it is a raw node from vimc-core, ignore the link for now | ||
298 | * TODO: remove this when there are no more raw nodes in the | ||
299 | * core and return error instead | ||
300 | */ | ||
301 | if (link->source->entity->obj_type == MEDIA_ENTITY_TYPE_BASE) | ||
302 | return 0; | ||
303 | |||
304 | ret = vimc_get_mbus_format(link->source, &source_fmt); | ||
305 | if (ret) | ||
306 | return ret; | ||
307 | |||
308 | ret = vimc_get_mbus_format(link->sink, &sink_fmt); | ||
309 | if (ret) | ||
310 | return ret; | ||
311 | |||
312 | pr_info("vimc link validate: " | ||
313 | "%s:src:%dx%d (0x%x, %d, %d, %d, %d) " | ||
314 | "%s:snk:%dx%d (0x%x, %d, %d, %d, %d)\n", | ||
315 | /* src */ | ||
316 | link->source->entity->name, | ||
317 | source_fmt.format.width, source_fmt.format.height, | ||
318 | source_fmt.format.code, source_fmt.format.colorspace, | ||
319 | source_fmt.format.quantization, source_fmt.format.xfer_func, | ||
320 | source_fmt.format.ycbcr_enc, | ||
321 | /* sink */ | ||
322 | link->sink->entity->name, | ||
323 | sink_fmt.format.width, sink_fmt.format.height, | ||
324 | sink_fmt.format.code, sink_fmt.format.colorspace, | ||
325 | sink_fmt.format.quantization, sink_fmt.format.xfer_func, | ||
326 | sink_fmt.format.ycbcr_enc); | ||
327 | |||
328 | /* The width, height and code must match. */ | ||
329 | if (source_fmt.format.width != sink_fmt.format.width | ||
330 | || source_fmt.format.height != sink_fmt.format.height | ||
331 | || source_fmt.format.code != sink_fmt.format.code) | ||
332 | return -EPIPE; | ||
333 | |||
334 | /* | ||
335 | * The field order must match, or the sink field order must be NONE | ||
336 | * to support interlaced hardware connected to bridges that support | ||
337 | * progressive formats only. | ||
338 | */ | ||
339 | if (source_fmt.format.field != sink_fmt.format.field && | ||
340 | sink_fmt.format.field != V4L2_FIELD_NONE) | ||
341 | return -EPIPE; | ||
342 | |||
343 | /* | ||
344 | * If colorspace is DEFAULT, then assume all the colorimetry is also | ||
345 | * DEFAULT, return 0 to skip comparing the other colorimetry parameters | ||
346 | */ | ||
347 | if (source_fmt.format.colorspace == V4L2_COLORSPACE_DEFAULT | ||
348 | || sink_fmt.format.colorspace == V4L2_COLORSPACE_DEFAULT) | ||
349 | return 0; | ||
350 | |||
351 | /* Colorspace must match. */ | ||
352 | if (source_fmt.format.colorspace != sink_fmt.format.colorspace) | ||
353 | return -EPIPE; | ||
354 | |||
355 | /* Colorimetry must match if they are not set to DEFAULT */ | ||
356 | if (source_fmt.format.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT | ||
357 | && sink_fmt.format.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT | ||
358 | && source_fmt.format.ycbcr_enc != sink_fmt.format.ycbcr_enc) | ||
359 | return -EPIPE; | ||
360 | |||
361 | if (source_fmt.format.quantization != V4L2_QUANTIZATION_DEFAULT | ||
362 | && sink_fmt.format.quantization != V4L2_QUANTIZATION_DEFAULT | ||
363 | && source_fmt.format.quantization != sink_fmt.format.quantization) | ||
364 | return -EPIPE; | ||
365 | |||
366 | if (source_fmt.format.xfer_func != V4L2_XFER_FUNC_DEFAULT | ||
367 | && sink_fmt.format.xfer_func != V4L2_XFER_FUNC_DEFAULT | ||
368 | && source_fmt.format.xfer_func != sink_fmt.format.xfer_func) | ||
369 | return -EPIPE; | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
255 | static const struct media_entity_operations vimc_ent_sd_mops = { | 374 | static const struct media_entity_operations vimc_ent_sd_mops = { |
256 | .link_validate = v4l2_subdev_link_validate, | 375 | .link_validate = vimc_link_validate, |
257 | }; | 376 | }; |
258 | 377 | ||
259 | int vimc_ent_sd_register(struct vimc_ent_device *ved, | 378 | int vimc_ent_sd_register(struct vimc_ent_device *ved, |