blob: b69805574c67575782604c1566b8d4947cd6b451 [file] [log] [blame]
Helen Fornazier5ba0ae42017-06-19 14:00:11 -03001/*
2 * vimc-common.c Virtual Media Controller Driver
3 *
4 * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17
18#include "vimc-common.h"
19
20static const struct vimc_pix_map vimc_pix_map_list[] = {
21 /* TODO: add all missing formats */
22
23 /* RGB formats */
24 {
25 .code = MEDIA_BUS_FMT_BGR888_1X24,
26 .pixelformat = V4L2_PIX_FMT_BGR24,
27 .bpp = 3,
28 },
29 {
30 .code = MEDIA_BUS_FMT_RGB888_1X24,
31 .pixelformat = V4L2_PIX_FMT_RGB24,
32 .bpp = 3,
33 },
34 {
35 .code = MEDIA_BUS_FMT_ARGB8888_1X32,
36 .pixelformat = V4L2_PIX_FMT_ARGB32,
37 .bpp = 4,
38 },
39
40 /* Bayer formats */
41 {
42 .code = MEDIA_BUS_FMT_SBGGR8_1X8,
43 .pixelformat = V4L2_PIX_FMT_SBGGR8,
44 .bpp = 1,
45 },
46 {
47 .code = MEDIA_BUS_FMT_SGBRG8_1X8,
48 .pixelformat = V4L2_PIX_FMT_SGBRG8,
49 .bpp = 1,
50 },
51 {
52 .code = MEDIA_BUS_FMT_SGRBG8_1X8,
53 .pixelformat = V4L2_PIX_FMT_SGRBG8,
54 .bpp = 1,
55 },
56 {
57 .code = MEDIA_BUS_FMT_SRGGB8_1X8,
58 .pixelformat = V4L2_PIX_FMT_SRGGB8,
59 .bpp = 1,
60 },
61 {
62 .code = MEDIA_BUS_FMT_SBGGR10_1X10,
63 .pixelformat = V4L2_PIX_FMT_SBGGR10,
64 .bpp = 2,
65 },
66 {
67 .code = MEDIA_BUS_FMT_SGBRG10_1X10,
68 .pixelformat = V4L2_PIX_FMT_SGBRG10,
69 .bpp = 2,
70 },
71 {
72 .code = MEDIA_BUS_FMT_SGRBG10_1X10,
73 .pixelformat = V4L2_PIX_FMT_SGRBG10,
74 .bpp = 2,
75 },
76 {
77 .code = MEDIA_BUS_FMT_SRGGB10_1X10,
78 .pixelformat = V4L2_PIX_FMT_SRGGB10,
79 .bpp = 2,
80 },
81
82 /* 10bit raw bayer a-law compressed to 8 bits */
83 {
84 .code = MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8,
85 .pixelformat = V4L2_PIX_FMT_SBGGR10ALAW8,
86 .bpp = 1,
87 },
88 {
89 .code = MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8,
90 .pixelformat = V4L2_PIX_FMT_SGBRG10ALAW8,
91 .bpp = 1,
92 },
93 {
94 .code = MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8,
95 .pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8,
96 .bpp = 1,
97 },
98 {
99 .code = MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8,
100 .pixelformat = V4L2_PIX_FMT_SRGGB10ALAW8,
101 .bpp = 1,
102 },
103
104 /* 10bit raw bayer DPCM compressed to 8 bits */
105 {
106 .code = MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8,
107 .pixelformat = V4L2_PIX_FMT_SBGGR10DPCM8,
108 .bpp = 1,
109 },
110 {
111 .code = MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8,
112 .pixelformat = V4L2_PIX_FMT_SGBRG10DPCM8,
113 .bpp = 1,
114 },
115 {
116 .code = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
117 .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8,
118 .bpp = 1,
119 },
120 {
121 .code = MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8,
122 .pixelformat = V4L2_PIX_FMT_SRGGB10DPCM8,
123 .bpp = 1,
124 },
125 {
126 .code = MEDIA_BUS_FMT_SBGGR12_1X12,
127 .pixelformat = V4L2_PIX_FMT_SBGGR12,
128 .bpp = 2,
129 },
130 {
131 .code = MEDIA_BUS_FMT_SGBRG12_1X12,
132 .pixelformat = V4L2_PIX_FMT_SGBRG12,
133 .bpp = 2,
134 },
135 {
136 .code = MEDIA_BUS_FMT_SGRBG12_1X12,
137 .pixelformat = V4L2_PIX_FMT_SGRBG12,
138 .bpp = 2,
139 },
140 {
141 .code = MEDIA_BUS_FMT_SRGGB12_1X12,
142 .pixelformat = V4L2_PIX_FMT_SRGGB12,
143 .bpp = 2,
144 },
145};
146
Helen Fornazier88ad71a2017-06-19 14:00:16 -0300147const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i)
148{
149 if (i >= ARRAY_SIZE(vimc_pix_map_list))
150 return NULL;
151
152 return &vimc_pix_map_list[i];
153}
154
Helen Fornazier5ba0ae42017-06-19 14:00:11 -0300155const struct vimc_pix_map *vimc_pix_map_by_code(u32 code)
156{
157 unsigned int i;
158
159 for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
160 if (vimc_pix_map_list[i].code == code)
161 return &vimc_pix_map_list[i];
162 }
163 return NULL;
164}
165
166const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat)
167{
168 unsigned int i;
169
170 for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
171 if (vimc_pix_map_list[i].pixelformat == pixelformat)
172 return &vimc_pix_map_list[i];
173 }
174 return NULL;
175}
176
177int vimc_propagate_frame(struct media_pad *src, const void *frame)
178{
179 struct media_link *link;
180
181 if (!(src->flags & MEDIA_PAD_FL_SOURCE))
182 return -EINVAL;
183
184 /* Send this frame to all sink pads that are direct linked */
185 list_for_each_entry(link, &src->entity->links, list) {
186 if (link->source == src &&
187 (link->flags & MEDIA_LNK_FL_ENABLED)) {
188 struct vimc_ent_device *ved = NULL;
189 struct media_entity *entity = link->sink->entity;
190
191 if (is_media_entity_v4l2_subdev(entity)) {
192 struct v4l2_subdev *sd =
193 container_of(entity, struct v4l2_subdev,
194 entity);
195 ved = v4l2_get_subdevdata(sd);
196 } else if (is_media_entity_v4l2_video_device(entity)) {
197 struct video_device *vdev =
198 container_of(entity,
199 struct video_device,
200 entity);
201 ved = video_get_drvdata(vdev);
202 }
203 if (ved && ved->process_frame)
204 ved->process_frame(ved, link->sink, frame);
205 }
206 }
207
208 return 0;
209}
210
211/* Helper function to allocate and initialize pads */
212struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag)
213{
214 struct media_pad *pads;
215 unsigned int i;
216
217 /* Allocate memory for the pads */
218 pads = kcalloc(num_pads, sizeof(*pads), GFP_KERNEL);
219 if (!pads)
220 return ERR_PTR(-ENOMEM);
221
222 /* Initialize the pads */
223 for (i = 0; i < num_pads; i++) {
224 pads[i].index = i;
225 pads[i].flags = pads_flag[i];
226 }
227
228 return pads;
229}
Helen Fornazierc1495432017-06-19 14:00:12 -0300230
Helen Fornazierbf5fb952017-06-19 14:00:13 -0300231int vimc_pipeline_s_stream(struct media_entity *ent, int enable)
232{
233 struct v4l2_subdev *sd;
234 struct media_pad *pad;
235 unsigned int i;
236 int ret;
237
238 for (i = 0; i < ent->num_pads; i++) {
239 if (ent->pads[i].flags & MEDIA_PAD_FL_SOURCE)
240 continue;
241
242 /* Start the stream in the subdevice direct connected */
243 pad = media_entity_remote_pad(&ent->pads[i]);
244
245 /*
246 * if this is a raw node from vimc-core, then there is
247 * nothing to activate
248 * TODO: remove this when there are no more raw nodes in the
249 * core and return error instead
250 */
251 if (pad->entity->obj_type == MEDIA_ENTITY_TYPE_BASE)
252 continue;
253
254 sd = media_entity_to_v4l2_subdev(pad->entity);
255 ret = v4l2_subdev_call(sd, video, s_stream, enable);
256 if (ret && ret != -ENOIOCTLCMD)
257 return ret;
258 }
259
260 return 0;
261}
262
Helen Fornazier288a22d2017-06-19 14:00:14 -0300263static int vimc_get_mbus_format(struct media_pad *pad,
264 struct v4l2_subdev_format *fmt)
265{
266 if (is_media_entity_v4l2_subdev(pad->entity)) {
267 struct v4l2_subdev *sd =
268 media_entity_to_v4l2_subdev(pad->entity);
269 int ret;
270
271 fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
272 fmt->pad = pad->index;
273
274 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt);
275 if (ret)
276 return ret;
277
278 } else if (is_media_entity_v4l2_video_device(pad->entity)) {
279 struct video_device *vdev = container_of(pad->entity,
280 struct video_device,
281 entity);
282 struct vimc_ent_device *ved = video_get_drvdata(vdev);
283 const struct vimc_pix_map *vpix;
284 struct v4l2_pix_format vdev_fmt;
285
286 if (!ved->vdev_get_format)
287 return -ENOIOCTLCMD;
288
289 ved->vdev_get_format(ved, &vdev_fmt);
290 vpix = vimc_pix_map_by_pixelformat(vdev_fmt.pixelformat);
291 v4l2_fill_mbus_format(&fmt->format, &vdev_fmt, vpix->code);
292 } else {
293 return -EINVAL;
294 }
295
296 return 0;
297}
298
299int vimc_link_validate(struct media_link *link)
300{
301 struct v4l2_subdev_format source_fmt, sink_fmt;
302 int ret;
303
304 /*
305 * if it is a raw node from vimc-core, ignore the link for now
306 * TODO: remove this when there are no more raw nodes in the
307 * core and return error instead
308 */
309 if (link->source->entity->obj_type == MEDIA_ENTITY_TYPE_BASE)
310 return 0;
311
312 ret = vimc_get_mbus_format(link->source, &source_fmt);
313 if (ret)
314 return ret;
315
316 ret = vimc_get_mbus_format(link->sink, &sink_fmt);
317 if (ret)
318 return ret;
319
320 pr_info("vimc link validate: "
321 "%s:src:%dx%d (0x%x, %d, %d, %d, %d) "
322 "%s:snk:%dx%d (0x%x, %d, %d, %d, %d)\n",
323 /* src */
324 link->source->entity->name,
325 source_fmt.format.width, source_fmt.format.height,
326 source_fmt.format.code, source_fmt.format.colorspace,
327 source_fmt.format.quantization, source_fmt.format.xfer_func,
328 source_fmt.format.ycbcr_enc,
329 /* sink */
330 link->sink->entity->name,
331 sink_fmt.format.width, sink_fmt.format.height,
332 sink_fmt.format.code, sink_fmt.format.colorspace,
333 sink_fmt.format.quantization, sink_fmt.format.xfer_func,
334 sink_fmt.format.ycbcr_enc);
335
336 /* The width, height and code must match. */
337 if (source_fmt.format.width != sink_fmt.format.width
338 || source_fmt.format.height != sink_fmt.format.height
339 || source_fmt.format.code != sink_fmt.format.code)
340 return -EPIPE;
341
342 /*
343 * The field order must match, or the sink field order must be NONE
344 * to support interlaced hardware connected to bridges that support
345 * progressive formats only.
346 */
347 if (source_fmt.format.field != sink_fmt.format.field &&
348 sink_fmt.format.field != V4L2_FIELD_NONE)
349 return -EPIPE;
350
351 /*
352 * If colorspace is DEFAULT, then assume all the colorimetry is also
353 * DEFAULT, return 0 to skip comparing the other colorimetry parameters
354 */
355 if (source_fmt.format.colorspace == V4L2_COLORSPACE_DEFAULT
356 || sink_fmt.format.colorspace == V4L2_COLORSPACE_DEFAULT)
357 return 0;
358
359 /* Colorspace must match. */
360 if (source_fmt.format.colorspace != sink_fmt.format.colorspace)
361 return -EPIPE;
362
363 /* Colorimetry must match if they are not set to DEFAULT */
364 if (source_fmt.format.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT
365 && sink_fmt.format.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT
366 && source_fmt.format.ycbcr_enc != sink_fmt.format.ycbcr_enc)
367 return -EPIPE;
368
369 if (source_fmt.format.quantization != V4L2_QUANTIZATION_DEFAULT
370 && sink_fmt.format.quantization != V4L2_QUANTIZATION_DEFAULT
371 && source_fmt.format.quantization != sink_fmt.format.quantization)
372 return -EPIPE;
373
374 if (source_fmt.format.xfer_func != V4L2_XFER_FUNC_DEFAULT
375 && sink_fmt.format.xfer_func != V4L2_XFER_FUNC_DEFAULT
376 && source_fmt.format.xfer_func != sink_fmt.format.xfer_func)
377 return -EPIPE;
378
379 return 0;
380}
381
Helen Fornazierc1495432017-06-19 14:00:12 -0300382static const struct media_entity_operations vimc_ent_sd_mops = {
Helen Fornazier288a22d2017-06-19 14:00:14 -0300383 .link_validate = vimc_link_validate,
Helen Fornazierc1495432017-06-19 14:00:12 -0300384};
385
386int vimc_ent_sd_register(struct vimc_ent_device *ved,
387 struct v4l2_subdev *sd,
388 struct v4l2_device *v4l2_dev,
389 const char *const name,
390 u32 function,
391 u16 num_pads,
392 const unsigned long *pads_flag,
393 const struct v4l2_subdev_ops *sd_ops,
394 void (*sd_destroy)(struct vimc_ent_device *))
395{
396 int ret;
397
398 /* Allocate the pads */
399 ved->pads = vimc_pads_init(num_pads, pads_flag);
400 if (IS_ERR(ved->pads))
401 return PTR_ERR(ved->pads);
402
403 /* Fill the vimc_ent_device struct */
404 ved->destroy = sd_destroy;
405 ved->ent = &sd->entity;
406
407 /* Initialize the subdev */
408 v4l2_subdev_init(sd, sd_ops);
409 sd->entity.function = function;
410 sd->entity.ops = &vimc_ent_sd_mops;
411 sd->owner = THIS_MODULE;
412 strlcpy(sd->name, name, sizeof(sd->name));
413 v4l2_set_subdevdata(sd, ved);
414
415 /* Expose this subdev to user space */
416 sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
417
418 /* Initialize the media entity */
419 ret = media_entity_pads_init(&sd->entity, num_pads, ved->pads);
420 if (ret)
421 goto err_clean_pads;
422
423 /* Register the subdev with the v4l2 and the media framework */
424 ret = v4l2_device_register_subdev(v4l2_dev, sd);
425 if (ret) {
426 dev_err(v4l2_dev->dev,
427 "%s: subdev register failed (err=%d)\n",
428 name, ret);
429 goto err_clean_m_ent;
430 }
431
432 return 0;
433
434err_clean_m_ent:
435 media_entity_cleanup(&sd->entity);
436err_clean_pads:
437 vimc_pads_cleanup(ved->pads);
438 return ret;
439}
440
441void vimc_ent_sd_unregister(struct vimc_ent_device *ved, struct v4l2_subdev *sd)
442{
443 v4l2_device_unregister_subdev(sd);
444 media_entity_cleanup(ved->ent);
445 vimc_pads_cleanup(ved->pads);
446}