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