619edbd9fbec6c362ccf288828dd5a355de58855
[openwrt/staging/blogic.git] /
1 From 68ed2d82179cf40557f448fd47979a54a12d6345 Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.com>
3 Date: Fri, 15 Oct 2021 17:57:27 +0100
4 Subject: [PATCH] media/bcm2835-unicam: Add support for configuration
5 via MC API
6
7 Adds Media Controller API support for more complex pipelines.
8 libcamera is about to switch to using this mechanism for configuring
9 sensors.
10
11 This can be enabled by either a module parameter, or device tree.
12
13 Various functions have been moved to group video-centric and
14 mc-centric functions together.
15
16 Based on a similar conversion done to ti-vpe.
17
18 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
19 ---
20 .../media/platform/bcm2835/bcm2835-unicam.c | 2125 ++++++++++-------
21 1 file changed, 1314 insertions(+), 811 deletions(-)
22
23 --- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
24 +++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
25 @@ -84,6 +84,10 @@ static int debug;
26 module_param(debug, int, 0644);
27 MODULE_PARM_DESC(debug, "Debug level 0-3");
28
29 +static int media_controller;
30 +module_param(media_controller, int, 0644);
31 +MODULE_PARM_DESC(media_controller, "Use media controller API");
32 +
33 #define unicam_dbg(level, dev, fmt, arg...) \
34 v4l2_dbg(level, debug, &(dev)->v4l2_dev, fmt, ##arg)
35 #define unicam_info(dev, fmt, arg...) \
36 @@ -120,7 +124,7 @@ MODULE_PARM_DESC(debug, "Debug level 0-3
37 #define MIN_WIDTH 16
38 #define MIN_HEIGHT 16
39 /* Default size of the embedded buffer */
40 -#define UNICAM_EMBEDDED_SIZE 8192
41 +#define UNICAM_EMBEDDED_SIZE 16384
42
43 /*
44 * Size of the dummy buffer. Can be any size really, but the DMA
45 @@ -134,6 +138,22 @@ enum pad_types {
46 MAX_NODES
47 };
48
49 +#define MASK_CS_DEFAULT BIT(V4L2_COLORSPACE_DEFAULT)
50 +#define MASK_CS_SMPTE170M BIT(V4L2_COLORSPACE_SMPTE170M)
51 +#define MASK_CS_SMPTE240M BIT(V4L2_COLORSPACE_SMPTE240M)
52 +#define MASK_CS_REC709 BIT(V4L2_COLORSPACE_REC709)
53 +#define MASK_CS_BT878 BIT(V4L2_COLORSPACE_BT878)
54 +#define MASK_CS_470_M BIT(V4L2_COLORSPACE_470_SYSTEM_M)
55 +#define MASK_CS_470_BG BIT(V4L2_COLORSPACE_470_SYSTEM_BG)
56 +#define MASK_CS_JPEG BIT(V4L2_COLORSPACE_JPEG)
57 +#define MASK_CS_SRGB BIT(V4L2_COLORSPACE_SRGB)
58 +#define MASK_CS_OPRGB BIT(V4L2_COLORSPACE_OPRGB)
59 +#define MASK_CS_BT2020 BIT(V4L2_COLORSPACE_BT2020)
60 +#define MASK_CS_RAW BIT(V4L2_COLORSPACE_RAW)
61 +#define MASK_CS_DCI_P3 BIT(V4L2_COLORSPACE_DCI_P3)
62 +
63 +#define MAX_COLORSPACE 32
64 +
65 /*
66 * struct unicam_fmt - Unicam media bus format information
67 * @pixelformat: V4L2 pixel format FCC identifier. 0 if n/a.
68 @@ -142,8 +162,14 @@ enum pad_types {
69 * @code: V4L2 media bus format code.
70 * @depth: Bits per pixel as delivered from the source.
71 * @csi_dt: CSI data type.
72 + * @valid_colorspaces: Bitmask of valid colorspaces so that the Media Controller
73 + * centric try_fmt can validate the colorspace and pass
74 + * v4l2-compliance.
75 * @check_variants: Flag to denote that there are multiple mediabus formats
76 * still in the list that could match this V4L2 format.
77 + * @mc_skip: Media Controller shouldn't list this format via ENUM_FMT as it is
78 + * a duplicate of an earlier format.
79 + * @metadata_fmt: This format only applies to the metadata pad.
80 */
81 struct unicam_fmt {
82 u32 fourcc;
83 @@ -151,7 +177,10 @@ struct unicam_fmt {
84 u32 code;
85 u8 depth;
86 u8 csi_dt;
87 - u8 check_variants;
88 + u32 valid_colorspaces;
89 + u8 check_variants:1;
90 + u8 mc_skip:1;
91 + u8 metadata_fmt:1;
92 };
93
94 static const struct unicam_fmt formats[] = {
95 @@ -162,173 +191,216 @@ static const struct unicam_fmt formats[]
96 .depth = 16,
97 .csi_dt = 0x1e,
98 .check_variants = 1,
99 + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 |
100 + MASK_CS_JPEG,
101 }, {
102 .fourcc = V4L2_PIX_FMT_UYVY,
103 .code = MEDIA_BUS_FMT_UYVY8_2X8,
104 .depth = 16,
105 .csi_dt = 0x1e,
106 .check_variants = 1,
107 + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 |
108 + MASK_CS_JPEG,
109 }, {
110 .fourcc = V4L2_PIX_FMT_YVYU,
111 .code = MEDIA_BUS_FMT_YVYU8_2X8,
112 .depth = 16,
113 .csi_dt = 0x1e,
114 .check_variants = 1,
115 + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 |
116 + MASK_CS_JPEG,
117 }, {
118 .fourcc = V4L2_PIX_FMT_VYUY,
119 .code = MEDIA_BUS_FMT_VYUY8_2X8,
120 .depth = 16,
121 .csi_dt = 0x1e,
122 .check_variants = 1,
123 + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 |
124 + MASK_CS_JPEG,
125 }, {
126 .fourcc = V4L2_PIX_FMT_YUYV,
127 .code = MEDIA_BUS_FMT_YUYV8_1X16,
128 .depth = 16,
129 .csi_dt = 0x1e,
130 + .mc_skip = 1,
131 + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 |
132 + MASK_CS_JPEG,
133 }, {
134 .fourcc = V4L2_PIX_FMT_UYVY,
135 .code = MEDIA_BUS_FMT_UYVY8_1X16,
136 .depth = 16,
137 .csi_dt = 0x1e,
138 + .mc_skip = 1,
139 + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 |
140 + MASK_CS_JPEG,
141 }, {
142 .fourcc = V4L2_PIX_FMT_YVYU,
143 .code = MEDIA_BUS_FMT_YVYU8_1X16,
144 .depth = 16,
145 .csi_dt = 0x1e,
146 + .mc_skip = 1,
147 + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 |
148 + MASK_CS_JPEG,
149 }, {
150 .fourcc = V4L2_PIX_FMT_VYUY,
151 .code = MEDIA_BUS_FMT_VYUY8_1X16,
152 .depth = 16,
153 .csi_dt = 0x1e,
154 + .mc_skip = 1,
155 + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 |
156 + MASK_CS_JPEG,
157 }, {
158 /* RGB Formats */
159 .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
160 .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
161 .depth = 16,
162 .csi_dt = 0x22,
163 + .valid_colorspaces = MASK_CS_SRGB,
164 }, {
165 .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
166 .code = MEDIA_BUS_FMT_RGB565_2X8_BE,
167 .depth = 16,
168 - .csi_dt = 0x22
169 + .csi_dt = 0x22,
170 + .valid_colorspaces = MASK_CS_SRGB,
171 }, {
172 .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
173 .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
174 .depth = 16,
175 .csi_dt = 0x21,
176 + .valid_colorspaces = MASK_CS_SRGB,
177 }, {
178 .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
179 .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE,
180 .depth = 16,
181 .csi_dt = 0x21,
182 + .valid_colorspaces = MASK_CS_SRGB,
183 }, {
184 .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */
185 .code = MEDIA_BUS_FMT_RGB888_1X24,
186 .depth = 24,
187 .csi_dt = 0x24,
188 + .valid_colorspaces = MASK_CS_SRGB,
189 }, {
190 .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */
191 .code = MEDIA_BUS_FMT_BGR888_1X24,
192 .depth = 24,
193 .csi_dt = 0x24,
194 + .valid_colorspaces = MASK_CS_SRGB,
195 }, {
196 .fourcc = V4L2_PIX_FMT_RGB32, /* argb */
197 .code = MEDIA_BUS_FMT_ARGB8888_1X32,
198 .depth = 32,
199 .csi_dt = 0x0,
200 + .valid_colorspaces = MASK_CS_SRGB,
201 }, {
202 /* Bayer Formats */
203 .fourcc = V4L2_PIX_FMT_SBGGR8,
204 .code = MEDIA_BUS_FMT_SBGGR8_1X8,
205 .depth = 8,
206 .csi_dt = 0x2a,
207 + .valid_colorspaces = MASK_CS_RAW,
208 }, {
209 .fourcc = V4L2_PIX_FMT_SGBRG8,
210 .code = MEDIA_BUS_FMT_SGBRG8_1X8,
211 .depth = 8,
212 .csi_dt = 0x2a,
213 + .valid_colorspaces = MASK_CS_RAW,
214 }, {
215 .fourcc = V4L2_PIX_FMT_SGRBG8,
216 .code = MEDIA_BUS_FMT_SGRBG8_1X8,
217 .depth = 8,
218 .csi_dt = 0x2a,
219 + .valid_colorspaces = MASK_CS_RAW,
220 }, {
221 .fourcc = V4L2_PIX_FMT_SRGGB8,
222 .code = MEDIA_BUS_FMT_SRGGB8_1X8,
223 .depth = 8,
224 .csi_dt = 0x2a,
225 + .valid_colorspaces = MASK_CS_RAW,
226 }, {
227 .fourcc = V4L2_PIX_FMT_SBGGR10P,
228 .repacked_fourcc = V4L2_PIX_FMT_SBGGR10,
229 .code = MEDIA_BUS_FMT_SBGGR10_1X10,
230 .depth = 10,
231 .csi_dt = 0x2b,
232 + .valid_colorspaces = MASK_CS_RAW,
233 }, {
234 .fourcc = V4L2_PIX_FMT_SGBRG10P,
235 .repacked_fourcc = V4L2_PIX_FMT_SGBRG10,
236 .code = MEDIA_BUS_FMT_SGBRG10_1X10,
237 .depth = 10,
238 .csi_dt = 0x2b,
239 + .valid_colorspaces = MASK_CS_RAW,
240 }, {
241 .fourcc = V4L2_PIX_FMT_SGRBG10P,
242 .repacked_fourcc = V4L2_PIX_FMT_SGRBG10,
243 .code = MEDIA_BUS_FMT_SGRBG10_1X10,
244 .depth = 10,
245 .csi_dt = 0x2b,
246 + .valid_colorspaces = MASK_CS_RAW,
247 }, {
248 .fourcc = V4L2_PIX_FMT_SRGGB10P,
249 .repacked_fourcc = V4L2_PIX_FMT_SRGGB10,
250 .code = MEDIA_BUS_FMT_SRGGB10_1X10,
251 .depth = 10,
252 .csi_dt = 0x2b,
253 + .valid_colorspaces = MASK_CS_RAW,
254 }, {
255 .fourcc = V4L2_PIX_FMT_SBGGR12P,
256 .repacked_fourcc = V4L2_PIX_FMT_SBGGR12,
257 .code = MEDIA_BUS_FMT_SBGGR12_1X12,
258 .depth = 12,
259 .csi_dt = 0x2c,
260 + .valid_colorspaces = MASK_CS_RAW,
261 }, {
262 .fourcc = V4L2_PIX_FMT_SGBRG12P,
263 .repacked_fourcc = V4L2_PIX_FMT_SGBRG12,
264 .code = MEDIA_BUS_FMT_SGBRG12_1X12,
265 .depth = 12,
266 .csi_dt = 0x2c,
267 + .valid_colorspaces = MASK_CS_RAW,
268 }, {
269 .fourcc = V4L2_PIX_FMT_SGRBG12P,
270 .repacked_fourcc = V4L2_PIX_FMT_SGRBG12,
271 .code = MEDIA_BUS_FMT_SGRBG12_1X12,
272 .depth = 12,
273 .csi_dt = 0x2c,
274 + .valid_colorspaces = MASK_CS_RAW,
275 }, {
276 .fourcc = V4L2_PIX_FMT_SRGGB12P,
277 .repacked_fourcc = V4L2_PIX_FMT_SRGGB12,
278 .code = MEDIA_BUS_FMT_SRGGB12_1X12,
279 .depth = 12,
280 .csi_dt = 0x2c,
281 + .valid_colorspaces = MASK_CS_RAW,
282 }, {
283 .fourcc = V4L2_PIX_FMT_SBGGR14P,
284 .repacked_fourcc = V4L2_PIX_FMT_SBGGR14,
285 .code = MEDIA_BUS_FMT_SBGGR14_1X14,
286 .depth = 14,
287 .csi_dt = 0x2d,
288 + .valid_colorspaces = MASK_CS_RAW,
289 }, {
290 .fourcc = V4L2_PIX_FMT_SGBRG14P,
291 .repacked_fourcc = V4L2_PIX_FMT_SGBRG14,
292 .code = MEDIA_BUS_FMT_SGBRG14_1X14,
293 .depth = 14,
294 .csi_dt = 0x2d,
295 + .valid_colorspaces = MASK_CS_RAW,
296 }, {
297 .fourcc = V4L2_PIX_FMT_SGRBG14P,
298 .repacked_fourcc = V4L2_PIX_FMT_SGRBG14,
299 .code = MEDIA_BUS_FMT_SGRBG14_1X14,
300 .depth = 14,
301 .csi_dt = 0x2d,
302 + .valid_colorspaces = MASK_CS_RAW,
303 }, {
304 .fourcc = V4L2_PIX_FMT_SRGGB14P,
305 .repacked_fourcc = V4L2_PIX_FMT_SRGGB14,
306 .code = MEDIA_BUS_FMT_SRGGB14_1X14,
307 .depth = 14,
308 .csi_dt = 0x2d,
309 + .valid_colorspaces = MASK_CS_RAW,
310 }, {
311 /*
312 * 16 bit Bayer formats could be supported, but there is no CSI2
313 @@ -341,30 +413,35 @@ static const struct unicam_fmt formats[]
314 .code = MEDIA_BUS_FMT_Y8_1X8,
315 .depth = 8,
316 .csi_dt = 0x2a,
317 + .valid_colorspaces = MASK_CS_RAW,
318 }, {
319 .fourcc = V4L2_PIX_FMT_Y10P,
320 .repacked_fourcc = V4L2_PIX_FMT_Y10,
321 .code = MEDIA_BUS_FMT_Y10_1X10,
322 .depth = 10,
323 .csi_dt = 0x2b,
324 + .valid_colorspaces = MASK_CS_RAW,
325 }, {
326 .fourcc = V4L2_PIX_FMT_Y12P,
327 .repacked_fourcc = V4L2_PIX_FMT_Y12,
328 .code = MEDIA_BUS_FMT_Y12_1X12,
329 .depth = 12,
330 .csi_dt = 0x2c,
331 + .valid_colorspaces = MASK_CS_RAW,
332 }, {
333 .fourcc = V4L2_PIX_FMT_Y14P,
334 .repacked_fourcc = V4L2_PIX_FMT_Y14,
335 .code = MEDIA_BUS_FMT_Y14_1X14,
336 .depth = 14,
337 .csi_dt = 0x2d,
338 + .valid_colorspaces = MASK_CS_RAW,
339 },
340 /* Embedded data format */
341 {
342 .fourcc = V4L2_META_FMT_SENSOR_DATA,
343 .code = MEDIA_BUS_FMT_SENSOR_DATA,
344 .depth = 8,
345 + .metadata_fmt = 1,
346 }
347 };
348
349 @@ -409,6 +486,7 @@ struct unicam_node {
350 struct unicam_device *dev;
351 struct media_pad pad;
352 unsigned int embedded_lines;
353 + struct media_pipeline pipe;
354 /*
355 * Dummy buffer intended to be used by unicam
356 * if we have no other queued buffers to swap to.
357 @@ -460,6 +538,8 @@ struct unicam_device {
358
359 struct unicam_node node[MAX_NODES];
360 struct v4l2_ctrl_handler ctrl_handler;
361 +
362 + bool mc_api;
363 };
364
365 static inline struct unicam_device *
366 @@ -909,6 +989,7 @@ static irqreturn_t unicam_isr(int irq, v
367 return IRQ_HANDLED;
368 }
369
370 +/* V4L2 Common IOCTLs */
371 static int unicam_querycap(struct file *file, void *priv,
372 struct v4l2_capability *cap)
373 {
374 @@ -926,6 +1007,38 @@ static int unicam_querycap(struct file *
375 return 0;
376 }
377
378 +static int unicam_log_status(struct file *file, void *fh)
379 +{
380 + struct unicam_node *node = video_drvdata(file);
381 + struct unicam_device *dev = node->dev;
382 + u32 reg;
383 +
384 + /* status for sub devices */
385 + v4l2_device_call_all(&dev->v4l2_dev, 0, core, log_status);
386 +
387 + unicam_info(dev, "-----Receiver status-----\n");
388 + unicam_info(dev, "V4L2 width/height: %ux%u\n",
389 + node->v_fmt.fmt.pix.width, node->v_fmt.fmt.pix.height);
390 + unicam_info(dev, "Mediabus format: %08x\n", node->fmt->code);
391 + unicam_info(dev, "V4L2 format: %08x\n",
392 + node->v_fmt.fmt.pix.pixelformat);
393 + reg = reg_read(dev, UNICAM_IPIPE);
394 + unicam_info(dev, "Unpacking/packing: %u / %u\n",
395 + get_field(reg, UNICAM_PUM_MASK),
396 + get_field(reg, UNICAM_PPM_MASK));
397 + unicam_info(dev, "----Live data----\n");
398 + unicam_info(dev, "Programmed stride: %4u\n",
399 + reg_read(dev, UNICAM_IBLS));
400 + unicam_info(dev, "Detected resolution: %ux%u\n",
401 + reg_read(dev, UNICAM_IHSTA),
402 + reg_read(dev, UNICAM_IVSTA));
403 + unicam_info(dev, "Write pointer: %08x\n",
404 + reg_read(dev, UNICAM_IBWP));
405 +
406 + return 0;
407 +}
408 +
409 +/* V4L2 Video Centric IOCTLs */
410 static int unicam_enum_fmt_vid_cap(struct file *file, void *priv,
411 struct v4l2_fmtdesc *f)
412 {
413 @@ -1270,6 +1383,727 @@ static int unicam_g_fmt_meta_cap(struct
414 return 0;
415 }
416
417 +static int unicam_enum_input(struct file *file, void *priv,
418 + struct v4l2_input *inp)
419 +{
420 + struct unicam_node *node = video_drvdata(file);
421 + struct unicam_device *dev = node->dev;
422 + int ret;
423 +
424 + if (inp->index != 0)
425 + return -EINVAL;
426 +
427 + inp->type = V4L2_INPUT_TYPE_CAMERA;
428 + if (v4l2_subdev_has_op(dev->sensor, video, s_dv_timings)) {
429 + inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;
430 + inp->std = 0;
431 + } else if (v4l2_subdev_has_op(dev->sensor, video, s_std)) {
432 + inp->capabilities = V4L2_IN_CAP_STD;
433 + if (v4l2_subdev_call(dev->sensor, video, g_tvnorms, &inp->std) < 0)
434 + inp->std = V4L2_STD_ALL;
435 + } else {
436 + inp->capabilities = 0;
437 + inp->std = 0;
438 + }
439 +
440 + if (v4l2_subdev_has_op(dev->sensor, video, g_input_status)) {
441 + ret = v4l2_subdev_call(dev->sensor, video, g_input_status,
442 + &inp->status);
443 + if (ret < 0)
444 + return ret;
445 + }
446 +
447 + snprintf(inp->name, sizeof(inp->name), "Camera 0");
448 + return 0;
449 +}
450 +
451 +static int unicam_g_input(struct file *file, void *priv, unsigned int *i)
452 +{
453 + *i = 0;
454 +
455 + return 0;
456 +}
457 +
458 +static int unicam_s_input(struct file *file, void *priv, unsigned int i)
459 +{
460 + /*
461 + * FIXME: Ideally we would like to be able to query the source
462 + * subdevice for information over the input connectors it supports,
463 + * and map that through in to a call to video_ops->s_routing.
464 + * There is no infrastructure support for defining that within
465 + * devicetree at present. Until that is implemented we can't
466 + * map a user physical connector number to s_routing input number.
467 + */
468 + if (i > 0)
469 + return -EINVAL;
470 +
471 + return 0;
472 +}
473 +
474 +static int unicam_querystd(struct file *file, void *priv,
475 + v4l2_std_id *std)
476 +{
477 + struct unicam_node *node = video_drvdata(file);
478 + struct unicam_device *dev = node->dev;
479 +
480 + return v4l2_subdev_call(dev->sensor, video, querystd, std);
481 +}
482 +
483 +static int unicam_g_std(struct file *file, void *priv, v4l2_std_id *std)
484 +{
485 + struct unicam_node *node = video_drvdata(file);
486 + struct unicam_device *dev = node->dev;
487 +
488 + return v4l2_subdev_call(dev->sensor, video, g_std, std);
489 +}
490 +
491 +static int unicam_s_std(struct file *file, void *priv, v4l2_std_id std)
492 +{
493 + struct unicam_node *node = video_drvdata(file);
494 + struct unicam_device *dev = node->dev;
495 + int ret;
496 + v4l2_std_id current_std;
497 +
498 + ret = v4l2_subdev_call(dev->sensor, video, g_std, &current_std);
499 + if (ret)
500 + return ret;
501 +
502 + if (std == current_std)
503 + return 0;
504 +
505 + if (vb2_is_busy(&node->buffer_queue))
506 + return -EBUSY;
507 +
508 + ret = v4l2_subdev_call(dev->sensor, video, s_std, std);
509 +
510 + /* Force recomputation of bytesperline */
511 + node->v_fmt.fmt.pix.bytesperline = 0;
512 +
513 + unicam_reset_format(node);
514 +
515 + return ret;
516 +}
517 +
518 +static int unicam_s_edid(struct file *file, void *priv, struct v4l2_edid *edid)
519 +{
520 + struct unicam_node *node = video_drvdata(file);
521 + struct unicam_device *dev = node->dev;
522 +
523 + return v4l2_subdev_call(dev->sensor, pad, set_edid, edid);
524 +}
525 +
526 +static int unicam_g_edid(struct file *file, void *priv, struct v4l2_edid *edid)
527 +{
528 + struct unicam_node *node = video_drvdata(file);
529 + struct unicam_device *dev = node->dev;
530 +
531 + return v4l2_subdev_call(dev->sensor, pad, get_edid, edid);
532 +}
533 +
534 +static int unicam_s_selection(struct file *file, void *priv,
535 + struct v4l2_selection *sel)
536 +{
537 + struct unicam_node *node = video_drvdata(file);
538 + struct unicam_device *dev = node->dev;
539 + struct v4l2_subdev_selection sdsel = {
540 + .which = V4L2_SUBDEV_FORMAT_ACTIVE,
541 + .target = sel->target,
542 + .flags = sel->flags,
543 + .r = sel->r,
544 + };
545 +
546 + if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
547 + return -EINVAL;
548 +
549 + return v4l2_subdev_call(dev->sensor, pad, set_selection, NULL, &sdsel);
550 +}
551 +
552 +static int unicam_g_selection(struct file *file, void *priv,
553 + struct v4l2_selection *sel)
554 +{
555 + struct unicam_node *node = video_drvdata(file);
556 + struct unicam_device *dev = node->dev;
557 + struct v4l2_subdev_selection sdsel = {
558 + .which = V4L2_SUBDEV_FORMAT_ACTIVE,
559 + .target = sel->target,
560 + };
561 + int ret;
562 +
563 + if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
564 + return -EINVAL;
565 +
566 + ret = v4l2_subdev_call(dev->sensor, pad, get_selection, NULL, &sdsel);
567 + if (!ret)
568 + sel->r = sdsel.r;
569 +
570 + return ret;
571 +}
572 +
573 +static int unicam_enum_framesizes(struct file *file, void *priv,
574 + struct v4l2_frmsizeenum *fsize)
575 +{
576 + struct unicam_node *node = video_drvdata(file);
577 + struct unicam_device *dev = node->dev;
578 + const struct unicam_fmt *fmt;
579 + struct v4l2_subdev_frame_size_enum fse;
580 + int ret;
581 +
582 + /* check for valid format */
583 + fmt = find_format_by_pix(dev, fsize->pixel_format);
584 + if (!fmt) {
585 + unicam_dbg(3, dev, "Invalid pixel code: %x\n",
586 + fsize->pixel_format);
587 + return -EINVAL;
588 + }
589 + fse.code = fmt->code;
590 +
591 + fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
592 + fse.index = fsize->index;
593 + fse.pad = node->src_pad_id;
594 +
595 + ret = v4l2_subdev_call(dev->sensor, pad, enum_frame_size, NULL, &fse);
596 + if (ret)
597 + return ret;
598 +
599 + unicam_dbg(1, dev, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n",
600 + __func__, fse.index, fse.code, fse.min_width, fse.max_width,
601 + fse.min_height, fse.max_height);
602 +
603 + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
604 + fsize->discrete.width = fse.max_width;
605 + fsize->discrete.height = fse.max_height;
606 +
607 + return 0;
608 +}
609 +
610 +static int unicam_enum_frameintervals(struct file *file, void *priv,
611 + struct v4l2_frmivalenum *fival)
612 +{
613 + struct unicam_node *node = video_drvdata(file);
614 + struct unicam_device *dev = node->dev;
615 + const struct unicam_fmt *fmt;
616 + struct v4l2_subdev_frame_interval_enum fie = {
617 + .index = fival->index,
618 + .pad = node->src_pad_id,
619 + .width = fival->width,
620 + .height = fival->height,
621 + .which = V4L2_SUBDEV_FORMAT_ACTIVE,
622 + };
623 + int ret;
624 +
625 + fmt = find_format_by_pix(dev, fival->pixel_format);
626 + if (!fmt)
627 + return -EINVAL;
628 +
629 + fie.code = fmt->code;
630 + ret = v4l2_subdev_call(dev->sensor, pad, enum_frame_interval,
631 + NULL, &fie);
632 + if (ret)
633 + return ret;
634 +
635 + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
636 + fival->discrete = fie.interval;
637 +
638 + return 0;
639 +}
640 +
641 +static int unicam_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
642 +{
643 + struct unicam_node *node = video_drvdata(file);
644 + struct unicam_device *dev = node->dev;
645 +
646 + return v4l2_g_parm_cap(video_devdata(file), dev->sensor, a);
647 +}
648 +
649 +static int unicam_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
650 +{
651 + struct unicam_node *node = video_drvdata(file);
652 + struct unicam_device *dev = node->dev;
653 +
654 + return v4l2_s_parm_cap(video_devdata(file), dev->sensor, a);
655 +}
656 +
657 +static int unicam_g_dv_timings(struct file *file, void *priv,
658 + struct v4l2_dv_timings *timings)
659 +{
660 + struct unicam_node *node = video_drvdata(file);
661 + struct unicam_device *dev = node->dev;
662 +
663 + return v4l2_subdev_call(dev->sensor, video, g_dv_timings, timings);
664 +}
665 +
666 +static int unicam_s_dv_timings(struct file *file, void *priv,
667 + struct v4l2_dv_timings *timings)
668 +{
669 + struct unicam_node *node = video_drvdata(file);
670 + struct unicam_device *dev = node->dev;
671 + struct v4l2_dv_timings current_timings;
672 + int ret;
673 +
674 + ret = v4l2_subdev_call(dev->sensor, video, g_dv_timings,
675 + &current_timings);
676 +
677 + if (ret < 0)
678 + return ret;
679 +
680 + if (v4l2_match_dv_timings(timings, &current_timings, 0, false))
681 + return 0;
682 +
683 + if (vb2_is_busy(&node->buffer_queue))
684 + return -EBUSY;
685 +
686 + ret = v4l2_subdev_call(dev->sensor, video, s_dv_timings, timings);
687 +
688 + /* Force recomputation of bytesperline */
689 + node->v_fmt.fmt.pix.bytesperline = 0;
690 +
691 + unicam_reset_format(node);
692 +
693 + return ret;
694 +}
695 +
696 +static int unicam_query_dv_timings(struct file *file, void *priv,
697 + struct v4l2_dv_timings *timings)
698 +{
699 + struct unicam_node *node = video_drvdata(file);
700 + struct unicam_device *dev = node->dev;
701 +
702 + return v4l2_subdev_call(dev->sensor, video, query_dv_timings, timings);
703 +}
704 +
705 +static int unicam_enum_dv_timings(struct file *file, void *priv,
706 + struct v4l2_enum_dv_timings *timings)
707 +{
708 + struct unicam_node *node = video_drvdata(file);
709 + struct unicam_device *dev = node->dev;
710 + int ret;
711 +
712 + timings->pad = node->src_pad_id;
713 + ret = v4l2_subdev_call(dev->sensor, pad, enum_dv_timings, timings);
714 + timings->pad = node->pad_id;
715 +
716 + return ret;
717 +}
718 +
719 +static int unicam_dv_timings_cap(struct file *file, void *priv,
720 + struct v4l2_dv_timings_cap *cap)
721 +{
722 + struct unicam_node *node = video_drvdata(file);
723 + struct unicam_device *dev = node->dev;
724 + int ret;
725 +
726 + cap->pad = node->src_pad_id;
727 + ret = v4l2_subdev_call(dev->sensor, pad, dv_timings_cap, cap);
728 + cap->pad = node->pad_id;
729 +
730 + return ret;
731 +}
732 +
733 +static int unicam_subscribe_event(struct v4l2_fh *fh,
734 + const struct v4l2_event_subscription *sub)
735 +{
736 + switch (sub->type) {
737 + case V4L2_EVENT_FRAME_SYNC:
738 + return v4l2_event_subscribe(fh, sub, 2, NULL);
739 + case V4L2_EVENT_SOURCE_CHANGE:
740 + return v4l2_event_subscribe(fh, sub, 4, NULL);
741 + }
742 +
743 + return v4l2_ctrl_subscribe_event(fh, sub);
744 +}
745 +
746 +static void unicam_notify(struct v4l2_subdev *sd,
747 + unsigned int notification, void *arg)
748 +{
749 + struct unicam_device *dev = to_unicam_device(sd->v4l2_dev);
750 +
751 + switch (notification) {
752 + case V4L2_DEVICE_NOTIFY_EVENT:
753 + v4l2_event_queue(&dev->node[IMAGE_PAD].video_dev, arg);
754 + break;
755 + default:
756 + break;
757 + }
758 +}
759 +
760 +/* unicam capture ioctl operations */
761 +static const struct v4l2_ioctl_ops unicam_ioctl_ops = {
762 + .vidioc_querycap = unicam_querycap,
763 + .vidioc_enum_fmt_vid_cap = unicam_enum_fmt_vid_cap,
764 + .vidioc_g_fmt_vid_cap = unicam_g_fmt_vid_cap,
765 + .vidioc_s_fmt_vid_cap = unicam_s_fmt_vid_cap,
766 + .vidioc_try_fmt_vid_cap = unicam_try_fmt_vid_cap,
767 +
768 + .vidioc_enum_fmt_meta_cap = unicam_enum_fmt_meta_cap,
769 + .vidioc_g_fmt_meta_cap = unicam_g_fmt_meta_cap,
770 + .vidioc_s_fmt_meta_cap = unicam_g_fmt_meta_cap,
771 + .vidioc_try_fmt_meta_cap = unicam_g_fmt_meta_cap,
772 +
773 + .vidioc_enum_input = unicam_enum_input,
774 + .vidioc_g_input = unicam_g_input,
775 + .vidioc_s_input = unicam_s_input,
776 +
777 + .vidioc_querystd = unicam_querystd,
778 + .vidioc_s_std = unicam_s_std,
779 + .vidioc_g_std = unicam_g_std,
780 +
781 + .vidioc_g_edid = unicam_g_edid,
782 + .vidioc_s_edid = unicam_s_edid,
783 +
784 + .vidioc_enum_framesizes = unicam_enum_framesizes,
785 + .vidioc_enum_frameintervals = unicam_enum_frameintervals,
786 +
787 + .vidioc_g_selection = unicam_g_selection,
788 + .vidioc_s_selection = unicam_s_selection,
789 +
790 + .vidioc_g_parm = unicam_g_parm,
791 + .vidioc_s_parm = unicam_s_parm,
792 +
793 + .vidioc_s_dv_timings = unicam_s_dv_timings,
794 + .vidioc_g_dv_timings = unicam_g_dv_timings,
795 + .vidioc_query_dv_timings = unicam_query_dv_timings,
796 + .vidioc_enum_dv_timings = unicam_enum_dv_timings,
797 + .vidioc_dv_timings_cap = unicam_dv_timings_cap,
798 +
799 + .vidioc_reqbufs = vb2_ioctl_reqbufs,
800 + .vidioc_create_bufs = vb2_ioctl_create_bufs,
801 + .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
802 + .vidioc_querybuf = vb2_ioctl_querybuf,
803 + .vidioc_qbuf = vb2_ioctl_qbuf,
804 + .vidioc_dqbuf = vb2_ioctl_dqbuf,
805 + .vidioc_expbuf = vb2_ioctl_expbuf,
806 + .vidioc_streamon = vb2_ioctl_streamon,
807 + .vidioc_streamoff = vb2_ioctl_streamoff,
808 +
809 + .vidioc_log_status = unicam_log_status,
810 + .vidioc_subscribe_event = unicam_subscribe_event,
811 + .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
812 +};
813 +
814 +/* V4L2 Media Controller Centric IOCTLs */
815 +
816 +static int unicam_mc_enum_fmt_vid_cap(struct file *file, void *priv,
817 + struct v4l2_fmtdesc *f)
818 +{
819 + int i, j;
820 +
821 + for (i = 0, j = 0; i < ARRAY_SIZE(formats); i++) {
822 + if (f->mbus_code && formats[i].code != f->mbus_code)
823 + continue;
824 + if (formats[i].mc_skip || formats[i].metadata_fmt)
825 + continue;
826 +
827 + if (formats[i].fourcc) {
828 + if (j == f->index) {
829 + f->pixelformat = formats[i].fourcc;
830 + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
831 + return 0;
832 + }
833 + j++;
834 + }
835 + if (formats[i].repacked_fourcc) {
836 + if (j == f->index) {
837 + f->pixelformat = formats[i].repacked_fourcc;
838 + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
839 + return 0;
840 + }
841 + j++;
842 + }
843 + }
844 +
845 + return -EINVAL;
846 +}
847 +
848 +static int unicam_mc_g_fmt_vid_cap(struct file *file, void *priv,
849 + struct v4l2_format *f)
850 +{
851 + struct unicam_node *node = video_drvdata(file);
852 +
853 + if (node->pad_id != IMAGE_PAD)
854 + return -EINVAL;
855 +
856 + *f = node->v_fmt;
857 +
858 + return 0;
859 +}
860 +
861 +static void unicam_mc_try_fmt(struct unicam_node *node, struct v4l2_format *f,
862 + const struct unicam_fmt **ret_fmt)
863 +{
864 + struct v4l2_pix_format *v4l2_format = &f->fmt.pix;
865 + struct unicam_device *dev = node->dev;
866 + const struct unicam_fmt *fmt;
867 + int is_rgb;
868 +
869 + /*
870 + * Default to the first format if the requested pixel format code isn't
871 + * supported.
872 + */
873 + fmt = find_format_by_pix(dev, v4l2_format->pixelformat);
874 + if (!fmt) {
875 + fmt = &formats[0];
876 + v4l2_format->pixelformat = fmt->fourcc;
877 + }
878 +
879 + unicam_calc_format_size_bpl(dev, fmt, f);
880 +
881 + if (v4l2_format->field == V4L2_FIELD_ANY)
882 + v4l2_format->field = V4L2_FIELD_NONE;
883 +
884 + if (ret_fmt)
885 + *ret_fmt = fmt;
886 +
887 + if (v4l2_format->colorspace >= MAX_COLORSPACE ||
888 + !(fmt->valid_colorspaces & (1 << v4l2_format->colorspace))) {
889 + v4l2_format->colorspace = __ffs(fmt->valid_colorspaces);
890 +
891 + v4l2_format->xfer_func =
892 + V4L2_MAP_XFER_FUNC_DEFAULT(v4l2_format->colorspace);
893 + v4l2_format->ycbcr_enc =
894 + V4L2_MAP_YCBCR_ENC_DEFAULT(v4l2_format->colorspace);
895 + is_rgb = v4l2_format->colorspace == V4L2_COLORSPACE_SRGB;
896 + v4l2_format->quantization =
897 + V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb,
898 + v4l2_format->colorspace,
899 + v4l2_format->ycbcr_enc);
900 + }
901 +
902 + unicam_dbg(3, dev, "%s: %08x %ux%u (bytesperline %u sizeimage %u)\n",
903 + __func__, v4l2_format->pixelformat,
904 + v4l2_format->width, v4l2_format->height,
905 + v4l2_format->bytesperline, v4l2_format->sizeimage);
906 +}
907 +
908 +static int unicam_mc_try_fmt_vid_cap(struct file *file, void *priv,
909 + struct v4l2_format *f)
910 +{
911 + struct unicam_node *node = video_drvdata(file);
912 +
913 + unicam_mc_try_fmt(node, f, NULL);
914 + return 0;
915 +}
916 +
917 +static int unicam_mc_s_fmt_vid_cap(struct file *file, void *priv,
918 + struct v4l2_format *f)
919 +{
920 + struct unicam_node *node = video_drvdata(file);
921 + struct unicam_device *dev = node->dev;
922 + const struct unicam_fmt *fmt;
923 +
924 + if (vb2_is_busy(&node->buffer_queue)) {
925 + unicam_dbg(3, dev, "%s device busy\n", __func__);
926 + return -EBUSY;
927 + }
928 +
929 + unicam_mc_try_fmt(node, f, &fmt);
930 +
931 + node->v_fmt = *f;
932 + node->fmt = fmt;
933 +
934 + return 0;
935 +}
936 +
937 +static int unicam_mc_enum_framesizes(struct file *file, void *fh,
938 + struct v4l2_frmsizeenum *fsize)
939 +{
940 + struct unicam_node *node = video_drvdata(file);
941 + struct unicam_device *dev = node->dev;
942 +
943 + if (fsize->index > 0)
944 + return -EINVAL;
945 +
946 + if (!find_format_by_pix(dev, fsize->pixel_format)) {
947 + unicam_dbg(3, dev, "Invalid pixel format 0x%08x\n",
948 + fsize->pixel_format);
949 + return -EINVAL;
950 + }
951 +
952 + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
953 + fsize->stepwise.min_width = MIN_WIDTH;
954 + fsize->stepwise.max_width = MAX_WIDTH;
955 + fsize->stepwise.step_width = 1;
956 + fsize->stepwise.min_height = MIN_HEIGHT;
957 + fsize->stepwise.max_height = MAX_HEIGHT;
958 + fsize->stepwise.step_height = 1;
959 +
960 + return 0;
961 +}
962 +
963 +static int unicam_mc_enum_fmt_meta_cap(struct file *file, void *priv,
964 + struct v4l2_fmtdesc *f)
965 +{
966 + int i, j;
967 +
968 + for (i = 0, j = 0; i < ARRAY_SIZE(formats); i++) {
969 + if (f->mbus_code && formats[i].code != f->mbus_code)
970 + continue;
971 + if (!formats[i].metadata_fmt)
972 + continue;
973 +
974 + if (formats[i].fourcc) {
975 + if (j == f->index) {
976 + f->pixelformat = formats[i].fourcc;
977 + f->type = V4L2_BUF_TYPE_META_CAPTURE;
978 + return 0;
979 + }
980 + j++;
981 + }
982 + }
983 +
984 + return -EINVAL;
985 +}
986 +
987 +static int unicam_mc_g_fmt_meta_cap(struct file *file, void *priv,
988 + struct v4l2_format *f)
989 +{
990 + struct unicam_node *node = video_drvdata(file);
991 +
992 + if (node->pad_id != METADATA_PAD)
993 + return -EINVAL;
994 +
995 + *f = node->v_fmt;
996 +
997 + return 0;
998 +}
999 +
1000 +static int unicam_mc_try_fmt_meta_cap(struct file *file, void *priv,
1001 + struct v4l2_format *f)
1002 +{
1003 + struct unicam_node *node = video_drvdata(file);
1004 +
1005 + if (node->pad_id != METADATA_PAD)
1006 + return -EINVAL;
1007 +
1008 + f->fmt.meta.dataformat = V4L2_META_FMT_SENSOR_DATA;
1009 +
1010 + return 0;
1011 +}
1012 +
1013 +static int unicam_mc_s_fmt_meta_cap(struct file *file, void *priv,
1014 + struct v4l2_format *f)
1015 +{
1016 + struct unicam_node *node = video_drvdata(file);
1017 +
1018 + if (node->pad_id != METADATA_PAD)
1019 + return -EINVAL;
1020 +
1021 + unicam_mc_try_fmt_meta_cap(file, priv, f);
1022 +
1023 + node->v_fmt = *f;
1024 +
1025 + return 0;
1026 +}
1027 +
1028 +static const struct v4l2_ioctl_ops unicam_mc_ioctl_ops = {
1029 + .vidioc_querycap = unicam_querycap,
1030 + .vidioc_enum_fmt_vid_cap = unicam_mc_enum_fmt_vid_cap,
1031 + .vidioc_g_fmt_vid_cap = unicam_mc_g_fmt_vid_cap,
1032 + .vidioc_try_fmt_vid_cap = unicam_mc_try_fmt_vid_cap,
1033 + .vidioc_s_fmt_vid_cap = unicam_mc_s_fmt_vid_cap,
1034 +
1035 + .vidioc_enum_fmt_meta_cap = unicam_mc_enum_fmt_meta_cap,
1036 + .vidioc_g_fmt_meta_cap = unicam_mc_g_fmt_meta_cap,
1037 + .vidioc_try_fmt_meta_cap = unicam_mc_try_fmt_meta_cap,
1038 + .vidioc_s_fmt_meta_cap = unicam_mc_s_fmt_meta_cap,
1039 +
1040 + .vidioc_enum_framesizes = unicam_mc_enum_framesizes,
1041 + .vidioc_reqbufs = vb2_ioctl_reqbufs,
1042 + .vidioc_create_bufs = vb2_ioctl_create_bufs,
1043 + .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
1044 + .vidioc_querybuf = vb2_ioctl_querybuf,
1045 + .vidioc_qbuf = vb2_ioctl_qbuf,
1046 + .vidioc_dqbuf = vb2_ioctl_dqbuf,
1047 + .vidioc_expbuf = vb2_ioctl_expbuf,
1048 + .vidioc_streamon = vb2_ioctl_streamon,
1049 + .vidioc_streamoff = vb2_ioctl_streamoff,
1050 +
1051 + .vidioc_log_status = unicam_log_status,
1052 + .vidioc_subscribe_event = unicam_subscribe_event,
1053 + .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
1054 +};
1055 +
1056 +static int
1057 +unicam_mc_subdev_link_validate_get_format(struct media_pad *pad,
1058 + struct v4l2_subdev_format *fmt)
1059 +{
1060 + if (is_media_entity_v4l2_subdev(pad->entity)) {
1061 + struct v4l2_subdev *sd =
1062 + media_entity_to_v4l2_subdev(pad->entity);
1063 +
1064 + fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
1065 + fmt->pad = pad->index;
1066 + return v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt);
1067 + }
1068 +
1069 + return -EINVAL;
1070 +}
1071 +
1072 +static int unicam_mc_video_link_validate(struct media_link *link)
1073 +{
1074 + struct video_device *vd = container_of(link->sink->entity,
1075 + struct video_device, entity);
1076 + struct unicam_node *node = container_of(vd, struct unicam_node,
1077 + video_dev);
1078 + struct unicam_device *unicam = node->dev;
1079 + struct v4l2_subdev_format source_fmt;
1080 + int ret;
1081 +
1082 + if (!media_entity_remote_pad(link->sink->entity->pads)) {
1083 + unicam_dbg(1, unicam,
1084 + "video node %s pad not connected\n", vd->name);
1085 + return -ENOTCONN;
1086 + }
1087 +
1088 + ret = unicam_mc_subdev_link_validate_get_format(link->source,
1089 + &source_fmt);
1090 + if (ret < 0)
1091 + return 0;
1092 +
1093 + if (node->pad_id == IMAGE_PAD) {
1094 + struct v4l2_pix_format *pix_fmt = &node->v_fmt.fmt.pix;
1095 + const struct unicam_fmt *fmt;
1096 +
1097 + if (source_fmt.format.width != pix_fmt->width ||
1098 + source_fmt.format.height != pix_fmt->height) {
1099 + unicam_err(unicam,
1100 + "Wrong width or height %ux%u (remote pad set to %ux%u)\n",
1101 + pix_fmt->width, pix_fmt->height,
1102 + source_fmt.format.width,
1103 + source_fmt.format.height);
1104 + return -EINVAL;
1105 + }
1106 +
1107 + fmt = find_format_by_code(source_fmt.format.code);
1108 +
1109 + if (!fmt || (fmt->fourcc != pix_fmt->pixelformat &&
1110 + fmt->repacked_fourcc != pix_fmt->pixelformat))
1111 + return -EINVAL;
1112 + } else {
1113 + struct v4l2_meta_format *meta_fmt = &node->v_fmt.fmt.meta;
1114 +
1115 + if (source_fmt.format.width != meta_fmt->buffersize ||
1116 + source_fmt.format.height != 1 ||
1117 + source_fmt.format.code != MEDIA_BUS_FMT_SENSOR_DATA) {
1118 + unicam_err(unicam,
1119 + "Wrong metadata width/height/code %ux%u %08x (remote pad set to %ux%u %08x)\n",
1120 + meta_fmt->buffersize, 1,
1121 + MEDIA_BUS_FMT_SENSOR_DATA,
1122 + source_fmt.format.width,
1123 + source_fmt.format.height,
1124 + source_fmt.format.code);
1125 + return -EINVAL;
1126 + }
1127 + }
1128 +
1129 + return 0;
1130 +}
1131 +
1132 +static const struct media_entity_operations unicam_mc_entity_ops = {
1133 + .link_validate = unicam_mc_video_link_validate,
1134 +};
1135 +
1136 +/* videobuf2 Operations */
1137 +
1138 static int unicam_queue_setup(struct vb2_queue *vq,
1139 unsigned int *nbuffers,
1140 unsigned int *nplanes,
1141 @@ -1667,6 +2501,12 @@ static int unicam_start_streaming(struct
1142 goto err_streaming;
1143 }
1144
1145 + ret = media_pipeline_start(&node->video_dev.entity, &node->pipe);
1146 + if (ret < 0) {
1147 + unicam_err(dev, "Failed to start media pipeline: %d\n", ret);
1148 + goto err_pm_put;
1149 + }
1150 +
1151 dev->active_data_lanes = dev->max_data_lanes;
1152
1153 if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) {
1154 @@ -1676,7 +2516,7 @@ static int unicam_start_streaming(struct
1155 0, &mbus_config);
1156 if (ret < 0 && ret != -ENOIOCTLCMD) {
1157 unicam_dbg(3, dev, "g_mbus_config failed\n");
1158 - goto err_pm_put;
1159 + goto error_pipeline;
1160 }
1161
1162 dev->active_data_lanes =
1163 @@ -1689,7 +2529,7 @@ static int unicam_start_streaming(struct
1164 dev->active_data_lanes,
1165 dev->max_data_lanes);
1166 ret = -EINVAL;
1167 - goto err_pm_put;
1168 + goto error_pipeline;
1169 }
1170 }
1171
1172 @@ -1699,13 +2539,13 @@ static int unicam_start_streaming(struct
1173 ret = clk_set_min_rate(dev->vpu_clock, MIN_VPU_CLOCK_RATE);
1174 if (ret) {
1175 unicam_err(dev, "failed to set up VPU clock\n");
1176 - goto err_pm_put;
1177 + goto error_pipeline;
1178 }
1179
1180 ret = clk_prepare_enable(dev->vpu_clock);
1181 if (ret) {
1182 unicam_err(dev, "Failed to enable VPU clock: %d\n", ret);
1183 - goto err_pm_put;
1184 + goto error_pipeline;
1185 }
1186
1187 ret = clk_set_rate(dev->clock, 100 * 1000 * 1000);
1188 @@ -1756,6 +2596,8 @@ err_vpu_clock:
1189 if (clk_set_min_rate(dev->vpu_clock, 0))
1190 unicam_err(dev, "failed to reset the VPU clock\n");
1191 clk_disable_unprepare(dev->vpu_clock);
1192 +error_pipeline:
1193 + media_pipeline_stop(&node->video_dev.entity);
1194 err_pm_put:
1195 unicam_runtime_put(dev);
1196 err_streaming:
1197 @@ -1783,6 +2625,8 @@ static void unicam_stop_streaming(struct
1198
1199 unicam_disable(dev);
1200
1201 + media_pipeline_stop(&node->video_dev.entity);
1202 +
1203 if (dev->clocks_enabled) {
1204 if (clk_set_min_rate(dev->vpu_clock, 0))
1205 unicam_err(dev, "failed to reset the min VPU clock\n");
1206 @@ -1807,379 +2651,6 @@ static void unicam_stop_streaming(struct
1207 unicam_return_buffers(node, VB2_BUF_STATE_ERROR);
1208 }
1209
1210 -static int unicam_enum_input(struct file *file, void *priv,
1211 - struct v4l2_input *inp)
1212 -{
1213 - struct unicam_node *node = video_drvdata(file);
1214 - struct unicam_device *dev = node->dev;
1215 - int ret;
1216 -
1217 - if (inp->index != 0)
1218 - return -EINVAL;
1219 -
1220 - inp->type = V4L2_INPUT_TYPE_CAMERA;
1221 - if (v4l2_subdev_has_op(dev->sensor, video, s_dv_timings)) {
1222 - inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;
1223 - inp->std = 0;
1224 - } else if (v4l2_subdev_has_op(dev->sensor, video, s_std)) {
1225 - inp->capabilities = V4L2_IN_CAP_STD;
1226 - if (v4l2_subdev_call(dev->sensor, video, g_tvnorms, &inp->std) < 0)
1227 - inp->std = V4L2_STD_ALL;
1228 - } else {
1229 - inp->capabilities = 0;
1230 - inp->std = 0;
1231 - }
1232 -
1233 - if (v4l2_subdev_has_op(dev->sensor, video, g_input_status)) {
1234 - ret = v4l2_subdev_call(dev->sensor, video, g_input_status,
1235 - &inp->status);
1236 - if (ret < 0)
1237 - return ret;
1238 - }
1239 -
1240 - snprintf(inp->name, sizeof(inp->name), "Camera 0");
1241 - return 0;
1242 -}
1243 -
1244 -static int unicam_g_input(struct file *file, void *priv, unsigned int *i)
1245 -{
1246 - *i = 0;
1247 -
1248 - return 0;
1249 -}
1250 -
1251 -static int unicam_s_input(struct file *file, void *priv, unsigned int i)
1252 -{
1253 - /*
1254 - * FIXME: Ideally we would like to be able to query the source
1255 - * subdevice for information over the input connectors it supports,
1256 - * and map that through in to a call to video_ops->s_routing.
1257 - * There is no infrastructure support for defining that within
1258 - * devicetree at present. Until that is implemented we can't
1259 - * map a user physical connector number to s_routing input number.
1260 - */
1261 - if (i > 0)
1262 - return -EINVAL;
1263 -
1264 - return 0;
1265 -}
1266 -
1267 -static int unicam_querystd(struct file *file, void *priv,
1268 - v4l2_std_id *std)
1269 -{
1270 - struct unicam_node *node = video_drvdata(file);
1271 - struct unicam_device *dev = node->dev;
1272 -
1273 - return v4l2_subdev_call(dev->sensor, video, querystd, std);
1274 -}
1275 -
1276 -static int unicam_g_std(struct file *file, void *priv, v4l2_std_id *std)
1277 -{
1278 - struct unicam_node *node = video_drvdata(file);
1279 - struct unicam_device *dev = node->dev;
1280 -
1281 - return v4l2_subdev_call(dev->sensor, video, g_std, std);
1282 -}
1283 -
1284 -static int unicam_s_std(struct file *file, void *priv, v4l2_std_id std)
1285 -{
1286 - struct unicam_node *node = video_drvdata(file);
1287 - struct unicam_device *dev = node->dev;
1288 - int ret;
1289 - v4l2_std_id current_std;
1290 -
1291 - ret = v4l2_subdev_call(dev->sensor, video, g_std, &current_std);
1292 - if (ret)
1293 - return ret;
1294 -
1295 - if (std == current_std)
1296 - return 0;
1297 -
1298 - if (vb2_is_busy(&node->buffer_queue))
1299 - return -EBUSY;
1300 -
1301 - ret = v4l2_subdev_call(dev->sensor, video, s_std, std);
1302 -
1303 - /* Force recomputation of bytesperline */
1304 - node->v_fmt.fmt.pix.bytesperline = 0;
1305 -
1306 - unicam_reset_format(node);
1307 -
1308 - return ret;
1309 -}
1310 -
1311 -static int unicam_s_edid(struct file *file, void *priv, struct v4l2_edid *edid)
1312 -{
1313 - struct unicam_node *node = video_drvdata(file);
1314 - struct unicam_device *dev = node->dev;
1315 -
1316 - return v4l2_subdev_call(dev->sensor, pad, set_edid, edid);
1317 -}
1318 -
1319 -static int unicam_g_edid(struct file *file, void *priv, struct v4l2_edid *edid)
1320 -{
1321 - struct unicam_node *node = video_drvdata(file);
1322 - struct unicam_device *dev = node->dev;
1323 -
1324 - return v4l2_subdev_call(dev->sensor, pad, get_edid, edid);
1325 -}
1326 -
1327 -static int unicam_s_selection(struct file *file, void *priv,
1328 - struct v4l2_selection *sel)
1329 -{
1330 - struct unicam_node *node = video_drvdata(file);
1331 - struct unicam_device *dev = node->dev;
1332 - struct v4l2_subdev_selection sdsel = {
1333 - .which = V4L2_SUBDEV_FORMAT_ACTIVE,
1334 - .target = sel->target,
1335 - .flags = sel->flags,
1336 - .r = sel->r,
1337 - };
1338 -
1339 - if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1340 - return -EINVAL;
1341 -
1342 - return v4l2_subdev_call(dev->sensor, pad, set_selection, NULL, &sdsel);
1343 -}
1344 -
1345 -static int unicam_g_selection(struct file *file, void *priv,
1346 - struct v4l2_selection *sel)
1347 -{
1348 - struct unicam_node *node = video_drvdata(file);
1349 - struct unicam_device *dev = node->dev;
1350 - struct v4l2_subdev_selection sdsel = {
1351 - .which = V4L2_SUBDEV_FORMAT_ACTIVE,
1352 - .target = sel->target,
1353 - };
1354 - int ret;
1355 -
1356 - if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1357 - return -EINVAL;
1358 -
1359 - ret = v4l2_subdev_call(dev->sensor, pad, get_selection, NULL, &sdsel);
1360 - if (!ret)
1361 - sel->r = sdsel.r;
1362 -
1363 - return ret;
1364 -}
1365 -
1366 -static int unicam_enum_framesizes(struct file *file, void *priv,
1367 - struct v4l2_frmsizeenum *fsize)
1368 -{
1369 - struct unicam_node *node = video_drvdata(file);
1370 - struct unicam_device *dev = node->dev;
1371 - const struct unicam_fmt *fmt;
1372 - struct v4l2_subdev_frame_size_enum fse;
1373 - int ret;
1374 -
1375 - /* check for valid format */
1376 - fmt = find_format_by_pix(dev, fsize->pixel_format);
1377 - if (!fmt) {
1378 - unicam_dbg(3, dev, "Invalid pixel code: %x\n",
1379 - fsize->pixel_format);
1380 - return -EINVAL;
1381 - }
1382 - fse.code = fmt->code;
1383 -
1384 - fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
1385 - fse.index = fsize->index;
1386 - fse.pad = node->src_pad_id;
1387 -
1388 - ret = v4l2_subdev_call(dev->sensor, pad, enum_frame_size, NULL, &fse);
1389 - if (ret)
1390 - return ret;
1391 -
1392 - unicam_dbg(1, dev, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n",
1393 - __func__, fse.index, fse.code, fse.min_width, fse.max_width,
1394 - fse.min_height, fse.max_height);
1395 -
1396 - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1397 - fsize->discrete.width = fse.max_width;
1398 - fsize->discrete.height = fse.max_height;
1399 -
1400 - return 0;
1401 -}
1402 -
1403 -static int unicam_enum_frameintervals(struct file *file, void *priv,
1404 - struct v4l2_frmivalenum *fival)
1405 -{
1406 - struct unicam_node *node = video_drvdata(file);
1407 - struct unicam_device *dev = node->dev;
1408 - const struct unicam_fmt *fmt;
1409 - struct v4l2_subdev_frame_interval_enum fie = {
1410 - .index = fival->index,
1411 - .pad = node->src_pad_id,
1412 - .width = fival->width,
1413 - .height = fival->height,
1414 - .which = V4L2_SUBDEV_FORMAT_ACTIVE,
1415 - };
1416 - int ret;
1417 -
1418 - fmt = find_format_by_pix(dev, fival->pixel_format);
1419 - if (!fmt)
1420 - return -EINVAL;
1421 -
1422 - fie.code = fmt->code;
1423 - ret = v4l2_subdev_call(dev->sensor, pad, enum_frame_interval,
1424 - NULL, &fie);
1425 - if (ret)
1426 - return ret;
1427 -
1428 - fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
1429 - fival->discrete = fie.interval;
1430 -
1431 - return 0;
1432 -}
1433 -
1434 -static int unicam_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
1435 -{
1436 - struct unicam_node *node = video_drvdata(file);
1437 - struct unicam_device *dev = node->dev;
1438 -
1439 - return v4l2_g_parm_cap(video_devdata(file), dev->sensor, a);
1440 -}
1441 -
1442 -static int unicam_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
1443 -{
1444 - struct unicam_node *node = video_drvdata(file);
1445 - struct unicam_device *dev = node->dev;
1446 -
1447 - return v4l2_s_parm_cap(video_devdata(file), dev->sensor, a);
1448 -}
1449 -
1450 -static int unicam_g_dv_timings(struct file *file, void *priv,
1451 - struct v4l2_dv_timings *timings)
1452 -{
1453 - struct unicam_node *node = video_drvdata(file);
1454 - struct unicam_device *dev = node->dev;
1455 -
1456 - return v4l2_subdev_call(dev->sensor, video, g_dv_timings, timings);
1457 -}
1458 -
1459 -static int unicam_s_dv_timings(struct file *file, void *priv,
1460 - struct v4l2_dv_timings *timings)
1461 -{
1462 - struct unicam_node *node = video_drvdata(file);
1463 - struct unicam_device *dev = node->dev;
1464 - struct v4l2_dv_timings current_timings;
1465 - int ret;
1466 -
1467 - ret = v4l2_subdev_call(dev->sensor, video, g_dv_timings,
1468 - &current_timings);
1469 -
1470 - if (ret < 0)
1471 - return ret;
1472 -
1473 - if (v4l2_match_dv_timings(timings, &current_timings, 0, false))
1474 - return 0;
1475 -
1476 - if (vb2_is_busy(&node->buffer_queue))
1477 - return -EBUSY;
1478 -
1479 - ret = v4l2_subdev_call(dev->sensor, video, s_dv_timings, timings);
1480 -
1481 - /* Force recomputation of bytesperline */
1482 - node->v_fmt.fmt.pix.bytesperline = 0;
1483 -
1484 - unicam_reset_format(node);
1485 -
1486 - return ret;
1487 -}
1488 -
1489 -static int unicam_query_dv_timings(struct file *file, void *priv,
1490 - struct v4l2_dv_timings *timings)
1491 -{
1492 - struct unicam_node *node = video_drvdata(file);
1493 - struct unicam_device *dev = node->dev;
1494 -
1495 - return v4l2_subdev_call(dev->sensor, video, query_dv_timings, timings);
1496 -}
1497 -
1498 -static int unicam_enum_dv_timings(struct file *file, void *priv,
1499 - struct v4l2_enum_dv_timings *timings)
1500 -{
1501 - struct unicam_node *node = video_drvdata(file);
1502 - struct unicam_device *dev = node->dev;
1503 - int ret;
1504 -
1505 - timings->pad = node->src_pad_id;
1506 - ret = v4l2_subdev_call(dev->sensor, pad, enum_dv_timings, timings);
1507 - timings->pad = node->pad_id;
1508 -
1509 - return ret;
1510 -}
1511 -
1512 -static int unicam_dv_timings_cap(struct file *file, void *priv,
1513 - struct v4l2_dv_timings_cap *cap)
1514 -{
1515 - struct unicam_node *node = video_drvdata(file);
1516 - struct unicam_device *dev = node->dev;
1517 - int ret;
1518 -
1519 - cap->pad = node->src_pad_id;
1520 - ret = v4l2_subdev_call(dev->sensor, pad, dv_timings_cap, cap);
1521 - cap->pad = node->pad_id;
1522 -
1523 - return ret;
1524 -}
1525 -
1526 -static int unicam_subscribe_event(struct v4l2_fh *fh,
1527 - const struct v4l2_event_subscription *sub)
1528 -{
1529 - switch (sub->type) {
1530 - case V4L2_EVENT_FRAME_SYNC:
1531 - return v4l2_event_subscribe(fh, sub, 2, NULL);
1532 - case V4L2_EVENT_SOURCE_CHANGE:
1533 - return v4l2_event_subscribe(fh, sub, 4, NULL);
1534 - }
1535 -
1536 - return v4l2_ctrl_subscribe_event(fh, sub);
1537 -}
1538 -
1539 -static int unicam_log_status(struct file *file, void *fh)
1540 -{
1541 - struct unicam_node *node = video_drvdata(file);
1542 - struct unicam_device *dev = node->dev;
1543 - u32 reg;
1544 -
1545 - /* status for sub devices */
1546 - v4l2_device_call_all(&dev->v4l2_dev, 0, core, log_status);
1547 -
1548 - unicam_info(dev, "-----Receiver status-----\n");
1549 - unicam_info(dev, "V4L2 width/height: %ux%u\n",
1550 - node->v_fmt.fmt.pix.width, node->v_fmt.fmt.pix.height);
1551 - unicam_info(dev, "Mediabus format: %08x\n", node->fmt->code);
1552 - unicam_info(dev, "V4L2 format: %08x\n",
1553 - node->v_fmt.fmt.pix.pixelformat);
1554 - reg = reg_read(dev, UNICAM_IPIPE);
1555 - unicam_info(dev, "Unpacking/packing: %u / %u\n",
1556 - get_field(reg, UNICAM_PUM_MASK),
1557 - get_field(reg, UNICAM_PPM_MASK));
1558 - unicam_info(dev, "----Live data----\n");
1559 - unicam_info(dev, "Programmed stride: %4u\n",
1560 - reg_read(dev, UNICAM_IBLS));
1561 - unicam_info(dev, "Detected resolution: %ux%u\n",
1562 - reg_read(dev, UNICAM_IHSTA),
1563 - reg_read(dev, UNICAM_IVSTA));
1564 - unicam_info(dev, "Write pointer: %08x\n",
1565 - reg_read(dev, UNICAM_IBWP));
1566 -
1567 - return 0;
1568 -}
1569 -
1570 -static void unicam_notify(struct v4l2_subdev *sd,
1571 - unsigned int notification, void *arg)
1572 -{
1573 - struct unicam_device *dev = to_unicam_device(sd->v4l2_dev);
1574 -
1575 - switch (notification) {
1576 - case V4L2_DEVICE_NOTIFY_EVENT:
1577 - v4l2_event_queue(&dev->node[IMAGE_PAD].video_dev, arg);
1578 - break;
1579 - default:
1580 - break;
1581 - }
1582 -}
1583
1584 static const struct vb2_ops unicam_video_qops = {
1585 .wait_prepare = vb2_ops_wait_prepare,
1586 @@ -2262,60 +2733,6 @@ static const struct v4l2_file_operations
1587 .mmap = vb2_fop_mmap,
1588 };
1589
1590 -/* unicam capture ioctl operations */
1591 -static const struct v4l2_ioctl_ops unicam_ioctl_ops = {
1592 - .vidioc_querycap = unicam_querycap,
1593 - .vidioc_enum_fmt_vid_cap = unicam_enum_fmt_vid_cap,
1594 - .vidioc_g_fmt_vid_cap = unicam_g_fmt_vid_cap,
1595 - .vidioc_s_fmt_vid_cap = unicam_s_fmt_vid_cap,
1596 - .vidioc_try_fmt_vid_cap = unicam_try_fmt_vid_cap,
1597 -
1598 - .vidioc_enum_fmt_meta_cap = unicam_enum_fmt_meta_cap,
1599 - .vidioc_g_fmt_meta_cap = unicam_g_fmt_meta_cap,
1600 - .vidioc_s_fmt_meta_cap = unicam_g_fmt_meta_cap,
1601 - .vidioc_try_fmt_meta_cap = unicam_g_fmt_meta_cap,
1602 -
1603 - .vidioc_enum_input = unicam_enum_input,
1604 - .vidioc_g_input = unicam_g_input,
1605 - .vidioc_s_input = unicam_s_input,
1606 -
1607 - .vidioc_querystd = unicam_querystd,
1608 - .vidioc_s_std = unicam_s_std,
1609 - .vidioc_g_std = unicam_g_std,
1610 -
1611 - .vidioc_g_edid = unicam_g_edid,
1612 - .vidioc_s_edid = unicam_s_edid,
1613 -
1614 - .vidioc_enum_framesizes = unicam_enum_framesizes,
1615 - .vidioc_enum_frameintervals = unicam_enum_frameintervals,
1616 -
1617 - .vidioc_g_selection = unicam_g_selection,
1618 - .vidioc_s_selection = unicam_s_selection,
1619 -
1620 - .vidioc_g_parm = unicam_g_parm,
1621 - .vidioc_s_parm = unicam_s_parm,
1622 -
1623 - .vidioc_s_dv_timings = unicam_s_dv_timings,
1624 - .vidioc_g_dv_timings = unicam_g_dv_timings,
1625 - .vidioc_query_dv_timings = unicam_query_dv_timings,
1626 - .vidioc_enum_dv_timings = unicam_enum_dv_timings,
1627 - .vidioc_dv_timings_cap = unicam_dv_timings_cap,
1628 -
1629 - .vidioc_reqbufs = vb2_ioctl_reqbufs,
1630 - .vidioc_create_bufs = vb2_ioctl_create_bufs,
1631 - .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
1632 - .vidioc_querybuf = vb2_ioctl_querybuf,
1633 - .vidioc_qbuf = vb2_ioctl_qbuf,
1634 - .vidioc_dqbuf = vb2_ioctl_dqbuf,
1635 - .vidioc_expbuf = vb2_ioctl_expbuf,
1636 - .vidioc_streamon = vb2_ioctl_streamon,
1637 - .vidioc_streamoff = vb2_ioctl_streamoff,
1638 -
1639 - .vidioc_log_status = unicam_log_status,
1640 - .vidioc_subscribe_event = unicam_subscribe_event,
1641 - .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
1642 -};
1643 -
1644 static int
1645 unicam_async_bound(struct v4l2_async_notifier *notifier,
1646 struct v4l2_subdev *subdev,
1647 @@ -2366,11 +2783,11 @@ static void unicam_node_release(struct v
1648 unicam_put(node->dev);
1649 }
1650
1651 -static int register_node(struct unicam_device *unicam, struct unicam_node *node,
1652 - enum v4l2_buf_type type, int pad_id)
1653 +static int unicam_set_default_format(struct unicam_device *unicam,
1654 + struct unicam_node *node,
1655 + int pad_id,
1656 + const struct unicam_fmt **ret_fmt)
1657 {
1658 - struct video_device *vdev;
1659 - struct vb2_queue *q;
1660 struct v4l2_mbus_framefmt mbus_fmt = {0};
1661 const struct unicam_fmt *fmt;
1662 int ret;
1663 @@ -2415,15 +2832,69 @@ static int register_node(struct unicam_d
1664 node->v_fmt.fmt.meta.dataformat = fmt->fourcc;
1665 }
1666
1667 + *ret_fmt = fmt;
1668 +
1669 + return 0;
1670 +}
1671 +
1672 +static void unicam_mc_set_default_format(struct unicam_node *node, int pad_id)
1673 +{
1674 + if (pad_id == IMAGE_PAD) {
1675 + struct v4l2_pix_format *pix_fmt = &node->v_fmt.fmt.pix;
1676 +
1677 + pix_fmt->width = 640;
1678 + pix_fmt->height = 480;
1679 + pix_fmt->field = V4L2_FIELD_NONE;
1680 + pix_fmt->colorspace = V4L2_COLORSPACE_SRGB;
1681 + pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
1682 + pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE;
1683 + pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB;
1684 + pix_fmt->pixelformat = formats[0].fourcc;
1685 + unicam_calc_format_size_bpl(node->dev, &formats[0],
1686 + &node->v_fmt);
1687 + node->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1688 +
1689 + node->fmt = &formats[0];
1690 + } else {
1691 + const struct unicam_fmt *fmt;
1692 +
1693 + /* Fix this node format as embedded data. */
1694 + fmt = find_format_by_code(MEDIA_BUS_FMT_SENSOR_DATA);
1695 + node->v_fmt.fmt.meta.dataformat = fmt->fourcc;
1696 + node->fmt = fmt;
1697 +
1698 + node->v_fmt.fmt.meta.buffersize = UNICAM_EMBEDDED_SIZE;
1699 + node->embedded_lines = 1;
1700 + node->v_fmt.type = V4L2_BUF_TYPE_META_CAPTURE;
1701 + }
1702 +}
1703 +
1704 +static int register_node(struct unicam_device *unicam, struct unicam_node *node,
1705 + enum v4l2_buf_type type, int pad_id)
1706 +{
1707 + struct video_device *vdev;
1708 + struct vb2_queue *q;
1709 + int ret;
1710 +
1711 node->dev = unicam;
1712 node->pad_id = pad_id;
1713 - node->fmt = fmt;
1714
1715 - /* Read current subdev format */
1716 - if (fmt)
1717 - unicam_reset_format(node);
1718 + if (!unicam->mc_api) {
1719 + const struct unicam_fmt *fmt;
1720
1721 - if (v4l2_subdev_has_op(unicam->sensor, video, s_std)) {
1722 + ret = unicam_set_default_format(unicam, node, pad_id, &fmt);
1723 + if (ret)
1724 + return ret;
1725 + node->fmt = fmt;
1726 + /* Read current subdev format */
1727 + if (fmt)
1728 + unicam_reset_format(node);
1729 + } else {
1730 + unicam_mc_set_default_format(node, pad_id);
1731 + }
1732 +
1733 + if (!unicam->mc_api &&
1734 + v4l2_subdev_has_op(unicam->sensor, video, s_std)) {
1735 v4l2_std_id tvnorms;
1736
1737 if (WARN_ON(!v4l2_subdev_has_op(unicam->sensor, video,
1738 @@ -2446,12 +2917,15 @@ static int register_node(struct unicam_d
1739
1740 vdev = &node->video_dev;
1741 if (pad_id == IMAGE_PAD) {
1742 - /* Add controls from the subdevice */
1743 - ret = v4l2_ctrl_add_handler(&unicam->ctrl_handler,
1744 - unicam->sensor->ctrl_handler, NULL,
1745 - true);
1746 - if (ret < 0)
1747 - return ret;
1748 + if (!unicam->mc_api) {
1749 + /* Add controls from the subdevice */
1750 + ret = v4l2_ctrl_add_handler(&unicam->ctrl_handler,
1751 + unicam->sensor->ctrl_handler,
1752 + NULL,
1753 + true);
1754 + if (ret < 0)
1755 + return ret;
1756 + }
1757
1758 /*
1759 * If the sensor subdevice has any controls, associate the node
1760 @@ -2483,7 +2957,8 @@ static int register_node(struct unicam_d
1761
1762 vdev->release = unicam_node_release;
1763 vdev->fops = &unicam_fops;
1764 - vdev->ioctl_ops = &unicam_ioctl_ops;
1765 + vdev->ioctl_ops = unicam->mc_api ? &unicam_mc_ioctl_ops :
1766 + &unicam_ioctl_ops;
1767 vdev->v4l2_dev = &unicam->v4l2_dev;
1768 vdev->vfl_dir = VFL_DIR_RX;
1769 vdev->queue = q;
1770 @@ -2491,6 +2966,10 @@ static int register_node(struct unicam_d
1771 vdev->device_caps = (pad_id == IMAGE_PAD) ?
1772 V4L2_CAP_VIDEO_CAPTURE : V4L2_CAP_META_CAPTURE;
1773 vdev->device_caps |= V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
1774 + if (unicam->mc_api) {
1775 + vdev->device_caps |= V4L2_CAP_IO_MC;
1776 + vdev->entity.ops = &unicam_mc_entity_ops;
1777 + }
1778
1779 /* Define the device names */
1780 snprintf(vdev->name, sizeof(vdev->name), "%s-%s", UNICAM_MODULE_NAME,
1781 @@ -2510,48 +2989,61 @@ static int register_node(struct unicam_d
1782 unicam_err(unicam, "Unable to allocate dummy buffer.\n");
1783 return -ENOMEM;
1784 }
1785 -
1786 - if (pad_id == METADATA_PAD ||
1787 - !v4l2_subdev_has_op(unicam->sensor, video, s_std)) {
1788 - v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_STD);
1789 - v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_STD);
1790 - v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUMSTD);
1791 - }
1792 - if (pad_id == METADATA_PAD ||
1793 - !v4l2_subdev_has_op(unicam->sensor, video, querystd))
1794 - v4l2_disable_ioctl(&node->video_dev, VIDIOC_QUERYSTD);
1795 - if (pad_id == METADATA_PAD ||
1796 - !v4l2_subdev_has_op(unicam->sensor, video, s_dv_timings)) {
1797 - v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_EDID);
1798 - v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_EDID);
1799 - v4l2_disable_ioctl(&node->video_dev, VIDIOC_DV_TIMINGS_CAP);
1800 - v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_DV_TIMINGS);
1801 - v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_DV_TIMINGS);
1802 - v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUM_DV_TIMINGS);
1803 - v4l2_disable_ioctl(&node->video_dev, VIDIOC_QUERY_DV_TIMINGS);
1804 - }
1805 - if (pad_id == METADATA_PAD ||
1806 - !v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_interval))
1807 - v4l2_disable_ioctl(&node->video_dev,
1808 - VIDIOC_ENUM_FRAMEINTERVALS);
1809 - if (pad_id == METADATA_PAD ||
1810 - !v4l2_subdev_has_op(unicam->sensor, video, g_frame_interval))
1811 - v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_PARM);
1812 - if (pad_id == METADATA_PAD ||
1813 - !v4l2_subdev_has_op(unicam->sensor, video, s_frame_interval))
1814 - v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_PARM);
1815 -
1816 - if (pad_id == METADATA_PAD ||
1817 - !v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_size))
1818 - v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUM_FRAMESIZES);
1819 -
1820 - if (node->pad_id == METADATA_PAD ||
1821 - !v4l2_subdev_has_op(unicam->sensor, pad, set_selection))
1822 - v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_SELECTION);
1823 -
1824 - if (node->pad_id == METADATA_PAD ||
1825 - !v4l2_subdev_has_op(unicam->sensor, pad, get_selection))
1826 - v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_SELECTION);
1827 + if (!unicam->mc_api) {
1828 + if (pad_id == METADATA_PAD ||
1829 + !v4l2_subdev_has_op(unicam->sensor, video, s_std)) {
1830 + v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_STD);
1831 + v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_STD);
1832 + v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUMSTD);
1833 + }
1834 + if (pad_id == METADATA_PAD ||
1835 + !v4l2_subdev_has_op(unicam->sensor, video, querystd))
1836 + v4l2_disable_ioctl(&node->video_dev, VIDIOC_QUERYSTD);
1837 + if (pad_id == METADATA_PAD ||
1838 + !v4l2_subdev_has_op(unicam->sensor, video, s_dv_timings)) {
1839 + v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_EDID);
1840 + v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_EDID);
1841 + v4l2_disable_ioctl(&node->video_dev,
1842 + VIDIOC_DV_TIMINGS_CAP);
1843 + v4l2_disable_ioctl(&node->video_dev,
1844 + VIDIOC_G_DV_TIMINGS);
1845 + v4l2_disable_ioctl(&node->video_dev,
1846 + VIDIOC_S_DV_TIMINGS);
1847 + v4l2_disable_ioctl(&node->video_dev,
1848 + VIDIOC_ENUM_DV_TIMINGS);
1849 + v4l2_disable_ioctl(&node->video_dev,
1850 + VIDIOC_QUERY_DV_TIMINGS);
1851 + }
1852 + if (pad_id == METADATA_PAD ||
1853 + !v4l2_subdev_has_op(unicam->sensor, pad,
1854 + enum_frame_interval))
1855 + v4l2_disable_ioctl(&node->video_dev,
1856 + VIDIOC_ENUM_FRAMEINTERVALS);
1857 + if (pad_id == METADATA_PAD ||
1858 + !v4l2_subdev_has_op(unicam->sensor, video,
1859 + g_frame_interval))
1860 + v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_PARM);
1861 + if (pad_id == METADATA_PAD ||
1862 + !v4l2_subdev_has_op(unicam->sensor, video,
1863 + s_frame_interval))
1864 + v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_PARM);
1865 +
1866 + if (pad_id == METADATA_PAD ||
1867 + !v4l2_subdev_has_op(unicam->sensor, pad,
1868 + enum_frame_size))
1869 + v4l2_disable_ioctl(&node->video_dev,
1870 + VIDIOC_ENUM_FRAMESIZES);
1871 +
1872 + if (node->pad_id == METADATA_PAD ||
1873 + !v4l2_subdev_has_op(unicam->sensor, pad, set_selection))
1874 + v4l2_disable_ioctl(&node->video_dev,
1875 + VIDIOC_S_SELECTION);
1876 +
1877 + if (node->pad_id == METADATA_PAD ||
1878 + !v4l2_subdev_has_op(unicam->sensor, pad, get_selection))
1879 + v4l2_disable_ioctl(&node->video_dev,
1880 + VIDIOC_G_SELECTION);
1881 + }
1882
1883 ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
1884 if (ret) {
1885 @@ -2618,7 +3110,7 @@ static int unicam_async_complete(struct
1886 if (unicam->sensor->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE) {
1887 if (source_pads < MAX_NODES) {
1888 unicam->node[source_pads].src_pad_id = i;
1889 - unicam_err(unicam, "source pad %u is index %u\n",
1890 + unicam_dbg(3, unicam, "source pad %u is index %u\n",
1891 source_pads, i);
1892 }
1893 source_pads++;
1894 @@ -2647,7 +3139,10 @@ static int unicam_async_complete(struct
1895 }
1896 }
1897
1898 - ret = v4l2_device_register_ro_subdev_nodes(&unicam->v4l2_dev);
1899 + if (unicam->mc_api)
1900 + ret = v4l2_device_register_subdev_nodes(&unicam->v4l2_dev);
1901 + else
1902 + ret = v4l2_device_register_ro_subdev_nodes(&unicam->v4l2_dev);
1903 if (ret) {
1904 unicam_err(unicam, "Unable to register subdev nodes.\n");
1905 goto unregister;
1906 @@ -2807,6 +3302,14 @@ static int unicam_probe(struct platform_
1907 kref_init(&unicam->kref);
1908 unicam->pdev = pdev;
1909
1910 + /*
1911 + * Adopt the current setting of the module parameter, and check if
1912 + * device tree requests it.
1913 + */
1914 + unicam->mc_api = media_controller;
1915 + if (of_property_read_bool(pdev->dev.of_node, "brcm,media-controller"))
1916 + unicam->mc_api = true;
1917 +
1918 unicam->base = devm_platform_ioremap_resource(pdev, 0);
1919 if (IS_ERR(unicam->base)) {
1920 unicam_err(unicam, "Failed to get main io block\n");