18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * vimc-common.c Virtual Media Controller Driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/init.h>
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "vimc-common.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci/*
148c2ecf20Sopenharmony_ci * NOTE: non-bayer formats need to come first (necessary for enum_mbus_code
158c2ecf20Sopenharmony_ci * in the scaler)
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_cistatic const struct vimc_pix_map vimc_pix_map_list[] = {
188c2ecf20Sopenharmony_ci	/* TODO: add all missing formats */
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci	/* RGB formats */
218c2ecf20Sopenharmony_ci	{
228c2ecf20Sopenharmony_ci		.code = {
238c2ecf20Sopenharmony_ci			MEDIA_BUS_FMT_BGR888_1X24,
248c2ecf20Sopenharmony_ci			MEDIA_BUS_FMT_BGR888_3X8
258c2ecf20Sopenharmony_ci		},
268c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_BGR24,
278c2ecf20Sopenharmony_ci		.bpp = 3,
288c2ecf20Sopenharmony_ci		.bayer = false,
298c2ecf20Sopenharmony_ci	},
308c2ecf20Sopenharmony_ci	{
318c2ecf20Sopenharmony_ci		.code = {
328c2ecf20Sopenharmony_ci			MEDIA_BUS_FMT_RGB888_1X24,
338c2ecf20Sopenharmony_ci			MEDIA_BUS_FMT_RGB888_2X12_BE,
348c2ecf20Sopenharmony_ci			MEDIA_BUS_FMT_RGB888_2X12_LE,
358c2ecf20Sopenharmony_ci			MEDIA_BUS_FMT_RGB888_3X8,
368c2ecf20Sopenharmony_ci			MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
378c2ecf20Sopenharmony_ci			MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,
388c2ecf20Sopenharmony_ci			MEDIA_BUS_FMT_RGB888_1X32_PADHI,
398c2ecf20Sopenharmony_ci			MEDIA_BUS_FMT_GBR888_1X24
408c2ecf20Sopenharmony_ci		},
418c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_RGB24,
428c2ecf20Sopenharmony_ci		.bpp = 3,
438c2ecf20Sopenharmony_ci		.bayer = false,
448c2ecf20Sopenharmony_ci	},
458c2ecf20Sopenharmony_ci	{
468c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_ARGB8888_1X32 },
478c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_ARGB32,
488c2ecf20Sopenharmony_ci		.bpp = 4,
498c2ecf20Sopenharmony_ci		.bayer = false,
508c2ecf20Sopenharmony_ci	},
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	/* Bayer formats */
538c2ecf20Sopenharmony_ci	{
548c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SBGGR8_1X8 },
558c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SBGGR8,
568c2ecf20Sopenharmony_ci		.bpp = 1,
578c2ecf20Sopenharmony_ci		.bayer = true,
588c2ecf20Sopenharmony_ci	},
598c2ecf20Sopenharmony_ci	{
608c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SGBRG8_1X8 },
618c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SGBRG8,
628c2ecf20Sopenharmony_ci		.bpp = 1,
638c2ecf20Sopenharmony_ci		.bayer = true,
648c2ecf20Sopenharmony_ci	},
658c2ecf20Sopenharmony_ci	{
668c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SGRBG8_1X8 },
678c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SGRBG8,
688c2ecf20Sopenharmony_ci		.bpp = 1,
698c2ecf20Sopenharmony_ci		.bayer = true,
708c2ecf20Sopenharmony_ci	},
718c2ecf20Sopenharmony_ci	{
728c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SRGGB8_1X8 },
738c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SRGGB8,
748c2ecf20Sopenharmony_ci		.bpp = 1,
758c2ecf20Sopenharmony_ci		.bayer = true,
768c2ecf20Sopenharmony_ci	},
778c2ecf20Sopenharmony_ci	{
788c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SBGGR10_1X10 },
798c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SBGGR10,
808c2ecf20Sopenharmony_ci		.bpp = 2,
818c2ecf20Sopenharmony_ci		.bayer = true,
828c2ecf20Sopenharmony_ci	},
838c2ecf20Sopenharmony_ci	{
848c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SGBRG10_1X10 },
858c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SGBRG10,
868c2ecf20Sopenharmony_ci		.bpp = 2,
878c2ecf20Sopenharmony_ci		.bayer = true,
888c2ecf20Sopenharmony_ci	},
898c2ecf20Sopenharmony_ci	{
908c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SGRBG10_1X10 },
918c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SGRBG10,
928c2ecf20Sopenharmony_ci		.bpp = 2,
938c2ecf20Sopenharmony_ci		.bayer = true,
948c2ecf20Sopenharmony_ci	},
958c2ecf20Sopenharmony_ci	{
968c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SRGGB10_1X10 },
978c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SRGGB10,
988c2ecf20Sopenharmony_ci		.bpp = 2,
998c2ecf20Sopenharmony_ci		.bayer = true,
1008c2ecf20Sopenharmony_ci	},
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	/* 10bit raw bayer a-law compressed to 8 bits */
1038c2ecf20Sopenharmony_ci	{
1048c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8 },
1058c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SBGGR10ALAW8,
1068c2ecf20Sopenharmony_ci		.bpp = 1,
1078c2ecf20Sopenharmony_ci		.bayer = true,
1088c2ecf20Sopenharmony_ci	},
1098c2ecf20Sopenharmony_ci	{
1108c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8 },
1118c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SGBRG10ALAW8,
1128c2ecf20Sopenharmony_ci		.bpp = 1,
1138c2ecf20Sopenharmony_ci		.bayer = true,
1148c2ecf20Sopenharmony_ci	},
1158c2ecf20Sopenharmony_ci	{
1168c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8 },
1178c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8,
1188c2ecf20Sopenharmony_ci		.bpp = 1,
1198c2ecf20Sopenharmony_ci		.bayer = true,
1208c2ecf20Sopenharmony_ci	},
1218c2ecf20Sopenharmony_ci	{
1228c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8 },
1238c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SRGGB10ALAW8,
1248c2ecf20Sopenharmony_ci		.bpp = 1,
1258c2ecf20Sopenharmony_ci		.bayer = true,
1268c2ecf20Sopenharmony_ci	},
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	/* 10bit raw bayer DPCM compressed to 8 bits */
1298c2ecf20Sopenharmony_ci	{
1308c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8 },
1318c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SBGGR10DPCM8,
1328c2ecf20Sopenharmony_ci		.bpp = 1,
1338c2ecf20Sopenharmony_ci		.bayer = true,
1348c2ecf20Sopenharmony_ci	},
1358c2ecf20Sopenharmony_ci	{
1368c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8 },
1378c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SGBRG10DPCM8,
1388c2ecf20Sopenharmony_ci		.bpp = 1,
1398c2ecf20Sopenharmony_ci		.bayer = true,
1408c2ecf20Sopenharmony_ci	},
1418c2ecf20Sopenharmony_ci	{
1428c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8 },
1438c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8,
1448c2ecf20Sopenharmony_ci		.bpp = 1,
1458c2ecf20Sopenharmony_ci		.bayer = true,
1468c2ecf20Sopenharmony_ci	},
1478c2ecf20Sopenharmony_ci	{
1488c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8 },
1498c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SRGGB10DPCM8,
1508c2ecf20Sopenharmony_ci		.bpp = 1,
1518c2ecf20Sopenharmony_ci		.bayer = true,
1528c2ecf20Sopenharmony_ci	},
1538c2ecf20Sopenharmony_ci	{
1548c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SBGGR12_1X12 },
1558c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SBGGR12,
1568c2ecf20Sopenharmony_ci		.bpp = 2,
1578c2ecf20Sopenharmony_ci		.bayer = true,
1588c2ecf20Sopenharmony_ci	},
1598c2ecf20Sopenharmony_ci	{
1608c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SGBRG12_1X12 },
1618c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SGBRG12,
1628c2ecf20Sopenharmony_ci		.bpp = 2,
1638c2ecf20Sopenharmony_ci		.bayer = true,
1648c2ecf20Sopenharmony_ci	},
1658c2ecf20Sopenharmony_ci	{
1668c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SGRBG12_1X12 },
1678c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SGRBG12,
1688c2ecf20Sopenharmony_ci		.bpp = 2,
1698c2ecf20Sopenharmony_ci		.bayer = true,
1708c2ecf20Sopenharmony_ci	},
1718c2ecf20Sopenharmony_ci	{
1728c2ecf20Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SRGGB12_1X12 },
1738c2ecf20Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SRGGB12,
1748c2ecf20Sopenharmony_ci		.bpp = 2,
1758c2ecf20Sopenharmony_ci		.bayer = true,
1768c2ecf20Sopenharmony_ci	},
1778c2ecf20Sopenharmony_ci};
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cibool vimc_is_source(struct media_entity *ent)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	unsigned int i;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	for (i = 0; i < ent->num_pads; i++)
1848c2ecf20Sopenharmony_ci		if (ent->pads[i].flags & MEDIA_PAD_FL_SINK)
1858c2ecf20Sopenharmony_ci			return false;
1868c2ecf20Sopenharmony_ci	return true;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ciconst struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	if (i >= ARRAY_SIZE(vimc_pix_map_list))
1928c2ecf20Sopenharmony_ci		return NULL;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	return &vimc_pix_map_list[i];
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ciu32 vimc_mbus_code_by_index(unsigned int index)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	unsigned int i, j;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
2028c2ecf20Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(vimc_pix_map_list[i].code); j++) {
2038c2ecf20Sopenharmony_ci			if (!vimc_pix_map_list[i].code[j])
2048c2ecf20Sopenharmony_ci				break;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci			if (!index)
2078c2ecf20Sopenharmony_ci				return vimc_pix_map_list[i].code[j];
2088c2ecf20Sopenharmony_ci			index--;
2098c2ecf20Sopenharmony_ci		}
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci	return 0;
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ciconst struct vimc_pix_map *vimc_pix_map_by_code(u32 code)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	unsigned int i, j;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
2198c2ecf20Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(vimc_pix_map_list[i].code); j++) {
2208c2ecf20Sopenharmony_ci			if (vimc_pix_map_list[i].code[j] == code)
2218c2ecf20Sopenharmony_ci				return &vimc_pix_map_list[i];
2228c2ecf20Sopenharmony_ci		}
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci	return NULL;
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ciconst struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	unsigned int i;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
2328c2ecf20Sopenharmony_ci		if (vimc_pix_map_list[i].pixelformat == pixelformat)
2338c2ecf20Sopenharmony_ci			return &vimc_pix_map_list[i];
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci	return NULL;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic int vimc_get_pix_format(struct media_pad *pad,
2398c2ecf20Sopenharmony_ci			       struct v4l2_pix_format *fmt)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	if (is_media_entity_v4l2_subdev(pad->entity)) {
2428c2ecf20Sopenharmony_ci		struct v4l2_subdev *sd =
2438c2ecf20Sopenharmony_ci			media_entity_to_v4l2_subdev(pad->entity);
2448c2ecf20Sopenharmony_ci		struct v4l2_subdev_format sd_fmt;
2458c2ecf20Sopenharmony_ci		const struct vimc_pix_map *pix_map;
2468c2ecf20Sopenharmony_ci		int ret;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci		sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
2498c2ecf20Sopenharmony_ci		sd_fmt.pad = pad->index;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci		ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt);
2528c2ecf20Sopenharmony_ci		if (ret)
2538c2ecf20Sopenharmony_ci			return ret;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci		v4l2_fill_pix_format(fmt, &sd_fmt.format);
2568c2ecf20Sopenharmony_ci		pix_map = vimc_pix_map_by_code(sd_fmt.format.code);
2578c2ecf20Sopenharmony_ci		fmt->pixelformat = pix_map->pixelformat;
2588c2ecf20Sopenharmony_ci	} else if (is_media_entity_v4l2_video_device(pad->entity)) {
2598c2ecf20Sopenharmony_ci		struct video_device *vdev = container_of(pad->entity,
2608c2ecf20Sopenharmony_ci							 struct video_device,
2618c2ecf20Sopenharmony_ci							 entity);
2628c2ecf20Sopenharmony_ci		struct vimc_ent_device *ved = video_get_drvdata(vdev);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci		if (!ved->vdev_get_format)
2658c2ecf20Sopenharmony_ci			return -ENOIOCTLCMD;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci		ved->vdev_get_format(ved, fmt);
2688c2ecf20Sopenharmony_ci	} else {
2698c2ecf20Sopenharmony_ci		return -EINVAL;
2708c2ecf20Sopenharmony_ci	}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	return 0;
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ciint vimc_vdev_link_validate(struct media_link *link)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	struct v4l2_pix_format source_fmt, sink_fmt;
2788c2ecf20Sopenharmony_ci	int ret;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	ret = vimc_get_pix_format(link->source, &source_fmt);
2818c2ecf20Sopenharmony_ci	if (ret)
2828c2ecf20Sopenharmony_ci		return ret;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	ret = vimc_get_pix_format(link->sink, &sink_fmt);
2858c2ecf20Sopenharmony_ci	if (ret)
2868c2ecf20Sopenharmony_ci		return ret;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	pr_info("vimc link validate: "
2898c2ecf20Sopenharmony_ci		"%s:src:%dx%d (0x%x, %d, %d, %d, %d) "
2908c2ecf20Sopenharmony_ci		"%s:snk:%dx%d (0x%x, %d, %d, %d, %d)\n",
2918c2ecf20Sopenharmony_ci		/* src */
2928c2ecf20Sopenharmony_ci		link->source->entity->name,
2938c2ecf20Sopenharmony_ci		source_fmt.width, source_fmt.height,
2948c2ecf20Sopenharmony_ci		source_fmt.pixelformat, source_fmt.colorspace,
2958c2ecf20Sopenharmony_ci		source_fmt.quantization, source_fmt.xfer_func,
2968c2ecf20Sopenharmony_ci		source_fmt.ycbcr_enc,
2978c2ecf20Sopenharmony_ci		/* sink */
2988c2ecf20Sopenharmony_ci		link->sink->entity->name,
2998c2ecf20Sopenharmony_ci		sink_fmt.width, sink_fmt.height,
3008c2ecf20Sopenharmony_ci		sink_fmt.pixelformat, sink_fmt.colorspace,
3018c2ecf20Sopenharmony_ci		sink_fmt.quantization, sink_fmt.xfer_func,
3028c2ecf20Sopenharmony_ci		sink_fmt.ycbcr_enc);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	/* The width, height and pixelformat must match. */
3058c2ecf20Sopenharmony_ci	if (source_fmt.width != sink_fmt.width ||
3068c2ecf20Sopenharmony_ci	    source_fmt.height != sink_fmt.height ||
3078c2ecf20Sopenharmony_ci	    source_fmt.pixelformat != sink_fmt.pixelformat)
3088c2ecf20Sopenharmony_ci		return -EPIPE;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	/*
3118c2ecf20Sopenharmony_ci	 * The field order must match, or the sink field order must be NONE
3128c2ecf20Sopenharmony_ci	 * to support interlaced hardware connected to bridges that support
3138c2ecf20Sopenharmony_ci	 * progressive formats only.
3148c2ecf20Sopenharmony_ci	 */
3158c2ecf20Sopenharmony_ci	if (source_fmt.field != sink_fmt.field &&
3168c2ecf20Sopenharmony_ci	    sink_fmt.field != V4L2_FIELD_NONE)
3178c2ecf20Sopenharmony_ci		return -EPIPE;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	/*
3208c2ecf20Sopenharmony_ci	 * If colorspace is DEFAULT, then assume all the colorimetry is also
3218c2ecf20Sopenharmony_ci	 * DEFAULT, return 0 to skip comparing the other colorimetry parameters
3228c2ecf20Sopenharmony_ci	 */
3238c2ecf20Sopenharmony_ci	if (source_fmt.colorspace == V4L2_COLORSPACE_DEFAULT ||
3248c2ecf20Sopenharmony_ci	    sink_fmt.colorspace == V4L2_COLORSPACE_DEFAULT)
3258c2ecf20Sopenharmony_ci		return 0;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	/* Colorspace must match. */
3288c2ecf20Sopenharmony_ci	if (source_fmt.colorspace != sink_fmt.colorspace)
3298c2ecf20Sopenharmony_ci		return -EPIPE;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	/* Colorimetry must match if they are not set to DEFAULT */
3328c2ecf20Sopenharmony_ci	if (source_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT &&
3338c2ecf20Sopenharmony_ci	    sink_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT &&
3348c2ecf20Sopenharmony_ci	    source_fmt.ycbcr_enc != sink_fmt.ycbcr_enc)
3358c2ecf20Sopenharmony_ci		return -EPIPE;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	if (source_fmt.quantization != V4L2_QUANTIZATION_DEFAULT &&
3388c2ecf20Sopenharmony_ci	    sink_fmt.quantization != V4L2_QUANTIZATION_DEFAULT &&
3398c2ecf20Sopenharmony_ci	    source_fmt.quantization != sink_fmt.quantization)
3408c2ecf20Sopenharmony_ci		return -EPIPE;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	if (source_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT &&
3438c2ecf20Sopenharmony_ci	    sink_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT &&
3448c2ecf20Sopenharmony_ci	    source_fmt.xfer_func != sink_fmt.xfer_func)
3458c2ecf20Sopenharmony_ci		return -EPIPE;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	return 0;
3488c2ecf20Sopenharmony_ci}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_cistatic const struct media_entity_operations vimc_ent_sd_mops = {
3518c2ecf20Sopenharmony_ci	.link_validate = v4l2_subdev_link_validate,
3528c2ecf20Sopenharmony_ci};
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ciint vimc_ent_sd_register(struct vimc_ent_device *ved,
3558c2ecf20Sopenharmony_ci			 struct v4l2_subdev *sd,
3568c2ecf20Sopenharmony_ci			 struct v4l2_device *v4l2_dev,
3578c2ecf20Sopenharmony_ci			 const char *const name,
3588c2ecf20Sopenharmony_ci			 u32 function,
3598c2ecf20Sopenharmony_ci			 u16 num_pads,
3608c2ecf20Sopenharmony_ci			 struct media_pad *pads,
3618c2ecf20Sopenharmony_ci			 const struct v4l2_subdev_ops *sd_ops)
3628c2ecf20Sopenharmony_ci{
3638c2ecf20Sopenharmony_ci	int ret;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	/* Fill the vimc_ent_device struct */
3668c2ecf20Sopenharmony_ci	ved->ent = &sd->entity;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	/* Initialize the subdev */
3698c2ecf20Sopenharmony_ci	v4l2_subdev_init(sd, sd_ops);
3708c2ecf20Sopenharmony_ci	sd->entity.function = function;
3718c2ecf20Sopenharmony_ci	sd->entity.ops = &vimc_ent_sd_mops;
3728c2ecf20Sopenharmony_ci	sd->owner = THIS_MODULE;
3738c2ecf20Sopenharmony_ci	strscpy(sd->name, name, sizeof(sd->name));
3748c2ecf20Sopenharmony_ci	v4l2_set_subdevdata(sd, ved);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	/* Expose this subdev to user space */
3778c2ecf20Sopenharmony_ci	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
3788c2ecf20Sopenharmony_ci	if (sd->ctrl_handler)
3798c2ecf20Sopenharmony_ci		sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	/* Initialize the media entity */
3828c2ecf20Sopenharmony_ci	ret = media_entity_pads_init(&sd->entity, num_pads, pads);
3838c2ecf20Sopenharmony_ci	if (ret)
3848c2ecf20Sopenharmony_ci		return ret;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	/* Register the subdev with the v4l2 and the media framework */
3878c2ecf20Sopenharmony_ci	ret = v4l2_device_register_subdev(v4l2_dev, sd);
3888c2ecf20Sopenharmony_ci	if (ret) {
3898c2ecf20Sopenharmony_ci		dev_err(v4l2_dev->dev,
3908c2ecf20Sopenharmony_ci			"%s: subdev register failed (err=%d)\n",
3918c2ecf20Sopenharmony_ci			name, ret);
3928c2ecf20Sopenharmony_ci		goto err_clean_m_ent;
3938c2ecf20Sopenharmony_ci	}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	return 0;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cierr_clean_m_ent:
3988c2ecf20Sopenharmony_ci	media_entity_cleanup(&sd->entity);
3998c2ecf20Sopenharmony_ci	return ret;
4008c2ecf20Sopenharmony_ci}
401