1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * vimc-common.c Virtual Media Controller Driver
4 *
5 * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
6 */
7
8#include <linux/init.h>
9#include <linux/module.h>
10
11#include "vimc-common.h"
12
13/*
14 * NOTE: non-bayer formats need to come first (necessary for enum_mbus_code
15 * in the scaler)
16 */
17static const struct vimc_pix_map vimc_pix_map_list[] = {
18	/* TODO: add all missing formats */
19
20	/* RGB formats */
21	{
22		.code = {
23			MEDIA_BUS_FMT_BGR888_1X24,
24			MEDIA_BUS_FMT_BGR888_3X8
25		},
26		.pixelformat = V4L2_PIX_FMT_BGR24,
27		.bpp = 3,
28		.bayer = false,
29	},
30	{
31		.code = {
32			MEDIA_BUS_FMT_RGB888_1X24,
33			MEDIA_BUS_FMT_RGB888_2X12_BE,
34			MEDIA_BUS_FMT_RGB888_2X12_LE,
35			MEDIA_BUS_FMT_RGB888_3X8,
36			MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
37			MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,
38			MEDIA_BUS_FMT_RGB888_1X32_PADHI,
39			MEDIA_BUS_FMT_GBR888_1X24
40		},
41		.pixelformat = V4L2_PIX_FMT_RGB24,
42		.bpp = 3,
43		.bayer = false,
44	},
45	{
46		.code = { MEDIA_BUS_FMT_ARGB8888_1X32 },
47		.pixelformat = V4L2_PIX_FMT_ARGB32,
48		.bpp = 4,
49		.bayer = false,
50	},
51
52	/* Bayer formats */
53	{
54		.code = { MEDIA_BUS_FMT_SBGGR8_1X8 },
55		.pixelformat = V4L2_PIX_FMT_SBGGR8,
56		.bpp = 1,
57		.bayer = true,
58	},
59	{
60		.code = { MEDIA_BUS_FMT_SGBRG8_1X8 },
61		.pixelformat = V4L2_PIX_FMT_SGBRG8,
62		.bpp = 1,
63		.bayer = true,
64	},
65	{
66		.code = { MEDIA_BUS_FMT_SGRBG8_1X8 },
67		.pixelformat = V4L2_PIX_FMT_SGRBG8,
68		.bpp = 1,
69		.bayer = true,
70	},
71	{
72		.code = { MEDIA_BUS_FMT_SRGGB8_1X8 },
73		.pixelformat = V4L2_PIX_FMT_SRGGB8,
74		.bpp = 1,
75		.bayer = true,
76	},
77	{
78		.code = { MEDIA_BUS_FMT_SBGGR10_1X10 },
79		.pixelformat = V4L2_PIX_FMT_SBGGR10,
80		.bpp = 2,
81		.bayer = true,
82	},
83	{
84		.code = { MEDIA_BUS_FMT_SGBRG10_1X10 },
85		.pixelformat = V4L2_PIX_FMT_SGBRG10,
86		.bpp = 2,
87		.bayer = true,
88	},
89	{
90		.code = { MEDIA_BUS_FMT_SGRBG10_1X10 },
91		.pixelformat = V4L2_PIX_FMT_SGRBG10,
92		.bpp = 2,
93		.bayer = true,
94	},
95	{
96		.code = { MEDIA_BUS_FMT_SRGGB10_1X10 },
97		.pixelformat = V4L2_PIX_FMT_SRGGB10,
98		.bpp = 2,
99		.bayer = true,
100	},
101
102	/* 10bit raw bayer a-law compressed to 8 bits */
103	{
104		.code = { MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8 },
105		.pixelformat = V4L2_PIX_FMT_SBGGR10ALAW8,
106		.bpp = 1,
107		.bayer = true,
108	},
109	{
110		.code = { MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8 },
111		.pixelformat = V4L2_PIX_FMT_SGBRG10ALAW8,
112		.bpp = 1,
113		.bayer = true,
114	},
115	{
116		.code = { MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8 },
117		.pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8,
118		.bpp = 1,
119		.bayer = true,
120	},
121	{
122		.code = { MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8 },
123		.pixelformat = V4L2_PIX_FMT_SRGGB10ALAW8,
124		.bpp = 1,
125		.bayer = true,
126	},
127
128	/* 10bit raw bayer DPCM compressed to 8 bits */
129	{
130		.code = { MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8 },
131		.pixelformat = V4L2_PIX_FMT_SBGGR10DPCM8,
132		.bpp = 1,
133		.bayer = true,
134	},
135	{
136		.code = { MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8 },
137		.pixelformat = V4L2_PIX_FMT_SGBRG10DPCM8,
138		.bpp = 1,
139		.bayer = true,
140	},
141	{
142		.code = { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8 },
143		.pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8,
144		.bpp = 1,
145		.bayer = true,
146	},
147	{
148		.code = { MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8 },
149		.pixelformat = V4L2_PIX_FMT_SRGGB10DPCM8,
150		.bpp = 1,
151		.bayer = true,
152	},
153	{
154		.code = { MEDIA_BUS_FMT_SBGGR12_1X12 },
155		.pixelformat = V4L2_PIX_FMT_SBGGR12,
156		.bpp = 2,
157		.bayer = true,
158	},
159	{
160		.code = { MEDIA_BUS_FMT_SGBRG12_1X12 },
161		.pixelformat = V4L2_PIX_FMT_SGBRG12,
162		.bpp = 2,
163		.bayer = true,
164	},
165	{
166		.code = { MEDIA_BUS_FMT_SGRBG12_1X12 },
167		.pixelformat = V4L2_PIX_FMT_SGRBG12,
168		.bpp = 2,
169		.bayer = true,
170	},
171	{
172		.code = { MEDIA_BUS_FMT_SRGGB12_1X12 },
173		.pixelformat = V4L2_PIX_FMT_SRGGB12,
174		.bpp = 2,
175		.bayer = true,
176	},
177};
178
179bool vimc_is_source(struct media_entity *ent)
180{
181	unsigned int i;
182
183	for (i = 0; i < ent->num_pads; i++)
184		if (ent->pads[i].flags & MEDIA_PAD_FL_SINK)
185			return false;
186	return true;
187}
188
189const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i)
190{
191	if (i >= ARRAY_SIZE(vimc_pix_map_list))
192		return NULL;
193
194	return &vimc_pix_map_list[i];
195}
196
197u32 vimc_mbus_code_by_index(unsigned int index)
198{
199	unsigned int i, j;
200
201	for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
202		for (j = 0; j < ARRAY_SIZE(vimc_pix_map_list[i].code); j++) {
203			if (!vimc_pix_map_list[i].code[j])
204				break;
205
206			if (!index)
207				return vimc_pix_map_list[i].code[j];
208			index--;
209		}
210	}
211	return 0;
212}
213
214const struct vimc_pix_map *vimc_pix_map_by_code(u32 code)
215{
216	unsigned int i, j;
217
218	for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
219		for (j = 0; j < ARRAY_SIZE(vimc_pix_map_list[i].code); j++) {
220			if (vimc_pix_map_list[i].code[j] == code)
221				return &vimc_pix_map_list[i];
222		}
223	}
224	return NULL;
225}
226
227const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat)
228{
229	unsigned int i;
230
231	for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
232		if (vimc_pix_map_list[i].pixelformat == pixelformat)
233			return &vimc_pix_map_list[i];
234	}
235	return NULL;
236}
237
238static int vimc_get_pix_format(struct media_pad *pad,
239			       struct v4l2_pix_format *fmt)
240{
241	if (is_media_entity_v4l2_subdev(pad->entity)) {
242		struct v4l2_subdev *sd =
243			media_entity_to_v4l2_subdev(pad->entity);
244		struct v4l2_subdev_format sd_fmt = {
245			.which = V4L2_SUBDEV_FORMAT_ACTIVE,
246			.pad = pad->index,
247		};
248		const struct vimc_pix_map *pix_map;
249		int ret;
250
251		ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt);
252		if (ret)
253			return ret;
254
255		v4l2_fill_pix_format(fmt, &sd_fmt.format);
256		pix_map = vimc_pix_map_by_code(sd_fmt.format.code);
257		fmt->pixelformat = pix_map->pixelformat;
258	} else if (is_media_entity_v4l2_video_device(pad->entity)) {
259		struct video_device *vdev = container_of(pad->entity,
260							 struct video_device,
261							 entity);
262		struct vimc_ent_device *ved = video_get_drvdata(vdev);
263
264		if (!ved->vdev_get_format)
265			return -ENOIOCTLCMD;
266
267		ved->vdev_get_format(ved, fmt);
268	} else {
269		return -EINVAL;
270	}
271
272	return 0;
273}
274
275int vimc_vdev_link_validate(struct media_link *link)
276{
277	struct v4l2_pix_format source_fmt, sink_fmt;
278	int ret;
279
280	ret = vimc_get_pix_format(link->source, &source_fmt);
281	if (ret)
282		return ret;
283
284	ret = vimc_get_pix_format(link->sink, &sink_fmt);
285	if (ret)
286		return ret;
287
288	pr_info("vimc link validate: "
289		"%s:src:%dx%d (0x%x, %d, %d, %d, %d) "
290		"%s:snk:%dx%d (0x%x, %d, %d, %d, %d)\n",
291		/* src */
292		link->source->entity->name,
293		source_fmt.width, source_fmt.height,
294		source_fmt.pixelformat, source_fmt.colorspace,
295		source_fmt.quantization, source_fmt.xfer_func,
296		source_fmt.ycbcr_enc,
297		/* sink */
298		link->sink->entity->name,
299		sink_fmt.width, sink_fmt.height,
300		sink_fmt.pixelformat, sink_fmt.colorspace,
301		sink_fmt.quantization, sink_fmt.xfer_func,
302		sink_fmt.ycbcr_enc);
303
304	/* The width, height and pixelformat must match. */
305	if (source_fmt.width != sink_fmt.width ||
306	    source_fmt.height != sink_fmt.height ||
307	    source_fmt.pixelformat != sink_fmt.pixelformat)
308		return -EPIPE;
309
310	/*
311	 * The field order must match, or the sink field order must be NONE
312	 * to support interlaced hardware connected to bridges that support
313	 * progressive formats only.
314	 */
315	if (source_fmt.field != sink_fmt.field &&
316	    sink_fmt.field != V4L2_FIELD_NONE)
317		return -EPIPE;
318
319	/*
320	 * If colorspace is DEFAULT, then assume all the colorimetry is also
321	 * DEFAULT, return 0 to skip comparing the other colorimetry parameters
322	 */
323	if (source_fmt.colorspace == V4L2_COLORSPACE_DEFAULT ||
324	    sink_fmt.colorspace == V4L2_COLORSPACE_DEFAULT)
325		return 0;
326
327	/* Colorspace must match. */
328	if (source_fmt.colorspace != sink_fmt.colorspace)
329		return -EPIPE;
330
331	/* Colorimetry must match if they are not set to DEFAULT */
332	if (source_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT &&
333	    sink_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT &&
334	    source_fmt.ycbcr_enc != sink_fmt.ycbcr_enc)
335		return -EPIPE;
336
337	if (source_fmt.quantization != V4L2_QUANTIZATION_DEFAULT &&
338	    sink_fmt.quantization != V4L2_QUANTIZATION_DEFAULT &&
339	    source_fmt.quantization != sink_fmt.quantization)
340		return -EPIPE;
341
342	if (source_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT &&
343	    sink_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT &&
344	    source_fmt.xfer_func != sink_fmt.xfer_func)
345		return -EPIPE;
346
347	return 0;
348}
349
350static const struct media_entity_operations vimc_ent_sd_mops = {
351	.link_validate = v4l2_subdev_link_validate,
352};
353
354int vimc_ent_sd_register(struct vimc_ent_device *ved,
355			 struct v4l2_subdev *sd,
356			 struct v4l2_device *v4l2_dev,
357			 const char *const name,
358			 u32 function,
359			 u16 num_pads,
360			 struct media_pad *pads,
361			 const struct v4l2_subdev_ops *sd_ops)
362{
363	int ret;
364
365	/* Fill the vimc_ent_device struct */
366	ved->ent = &sd->entity;
367
368	/* Initialize the subdev */
369	v4l2_subdev_init(sd, sd_ops);
370	sd->entity.function = function;
371	sd->entity.ops = &vimc_ent_sd_mops;
372	sd->owner = THIS_MODULE;
373	strscpy(sd->name, name, sizeof(sd->name));
374	v4l2_set_subdevdata(sd, ved);
375
376	/* Expose this subdev to user space */
377	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
378	if (sd->ctrl_handler)
379		sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
380
381	/* Initialize the media entity */
382	ret = media_entity_pads_init(&sd->entity, num_pads, pads);
383	if (ret)
384		return ret;
385
386	/* Register the subdev with the v4l2 and the media framework */
387	ret = v4l2_device_register_subdev(v4l2_dev, sd);
388	if (ret) {
389		dev_err(v4l2_dev->dev,
390			"%s: subdev register failed (err=%d)\n",
391			name, ret);
392		goto err_clean_m_ent;
393	}
394
395	return 0;
396
397err_clean_m_ent:
398	media_entity_cleanup(&sd->entity);
399	return ret;
400}
401