58c055b7375d2fd704ed49b950d622052d64c3cb
[openwrt/staging/jow.git] /
1 From cfa60cc9d644b8d12886332eceb7449e7397dff2 Mon Sep 17 00:00:00 2001
2 From: Naushir Patuck <naush@raspberrypi.com>
3 Date: Thu, 23 Apr 2020 10:17:37 +0100
4 Subject: [PATCH] staging: vc04_services: ISP: Add a more complex ISP
5 processing component
6
7 Driver for the BCM2835 ISP hardware block. This driver uses the MMAL
8 component to program the ISP hardware through the VC firmware.
9
10 The ISP component can produce two video stream outputs, and Bayer
11 image statistics. This can't be encompassed in a simple V4L2
12 M2M device, so create a new device that registers 4 video nodes.
13
14 This patch squashes all the development patches from the earlier
15 rpi-5.4.y branch into one
16
17 Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
18 ---
19 MAINTAINERS | 9 +
20 drivers/staging/vc04_services/Kconfig | 1 +
21 drivers/staging/vc04_services/Makefile | 1 +
22 .../staging/vc04_services/bcm2835-isp/Kconfig | 14 +
23 .../vc04_services/bcm2835-isp/Makefile | 8 +
24 .../bcm2835-isp/bcm2835-isp-ctrls.h | 67 +
25 .../bcm2835-isp/bcm2835-isp-fmts.h | 353 ++++
26 .../bcm2835-isp/bcm2835-v4l2-isp.c | 1696 +++++++++++++++++
27 .../vc04_services/vchiq-mmal/mmal-encodings.h | 4 +
28 .../vchiq-mmal/mmal-parameters.h | 153 +-
29 10 files changed, 2305 insertions(+), 1 deletion(-)
30 create mode 100644 drivers/staging/vc04_services/bcm2835-isp/Kconfig
31 create mode 100644 drivers/staging/vc04_services/bcm2835-isp/Makefile
32 create mode 100644 drivers/staging/vc04_services/bcm2835-isp/bcm2835-isp-ctrls.h
33 create mode 100644 drivers/staging/vc04_services/bcm2835-isp/bcm2835-isp-fmts.h
34 create mode 100644 drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c
35
36 --- a/MAINTAINERS
37 +++ b/MAINTAINERS
38 @@ -4044,6 +4044,15 @@ S: Maintained
39 F: drivers/media/platform/bcm2835/
40 F: Documentation/devicetree/bindings/media/brcm,bcm2835-unicam.yaml
41
42 +BROADCOM BCM2835 ISP DRIVER
43 +M: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
44 +L: linux-media@vger.kernel.org
45 +S: Maintained
46 +F: Documentation/media/uapi/v4l/pixfmt-meta-bcm2835-isp-stats.rst
47 +F: Documentation/media/v4l-drivers/bcm2835-isp.rst
48 +F: drivers/staging/vc04_services/bcm2835-isp
49 +F: include/uapi/linux/bcm2835-isp.h
50 +
51 BROADCOM BCM47XX MIPS ARCHITECTURE
52 M: Hauke Mehrtens <hauke@hauke-m.de>
53 M: Rafał Miłecki <zajec5@gmail.com>
54 --- a/drivers/staging/vc04_services/Kconfig
55 +++ b/drivers/staging/vc04_services/Kconfig
56 @@ -46,6 +46,7 @@ source "drivers/staging/vc04_services/bc
57
58 source "drivers/staging/vc04_services/vc-sm-cma/Kconfig"
59 source "drivers/staging/vc04_services/bcm2835-codec/Kconfig"
60 +source "drivers/staging/vc04_services/bcm2835-isp/Kconfig"
61
62 source "drivers/staging/vc04_services/vchiq-mmal/Kconfig"
63
64 --- a/drivers/staging/vc04_services/Makefile
65 +++ b/drivers/staging/vc04_services/Makefile
66 @@ -16,6 +16,7 @@ obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-
67 obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/
68 obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma/
69 obj-$(CONFIG_VIDEO_CODEC_BCM2835) += bcm2835-codec/
70 +obj-$(CONFIG_VIDEO_ISP_BCM2835) += bcm2835-isp/
71
72 ccflags-y += -I $(srctree)/$(src)/include
73
74 --- /dev/null
75 +++ b/drivers/staging/vc04_services/bcm2835-isp/Kconfig
76 @@ -0,0 +1,14 @@
77 +config VIDEO_ISP_BCM2835
78 + tristate "BCM2835 ISP support"
79 + depends on MEDIA_SUPPORT
80 + depends on VIDEO_DEV && (ARCH_BCM2835 || COMPILE_TEST)
81 + depends on MEDIA_CONTROLLER
82 + select BCM2835_VCHIQ_MMAL
83 + select VIDEOBUF2_DMA_CONTIG
84 + help
85 + This is the V4L2 driver for the Broadcom BCM2835 ISP hardware.
86 + This operates over the VCHIQ interface to a service running on
87 + VideoCore.
88 +
89 + To compile this driver as a module, choose M here: the module
90 + will be called bcm2835-isp.
91 --- /dev/null
92 +++ b/drivers/staging/vc04_services/bcm2835-isp/Makefile
93 @@ -0,0 +1,8 @@
94 +# SPDX-License-Identifier: GPL-2.0
95 +bcm2835-isp-objs := bcm2835-v4l2-isp.o
96 +
97 +obj-$(CONFIG_VIDEO_ISP_BCM2835) += bcm2835-isp.o
98 +
99 +ccflags-y += \
100 + -I$(srctree)/drivers/staging/vc04_services \
101 + -D__VCCOREVER__=0x04000000
102 --- /dev/null
103 +++ b/drivers/staging/vc04_services/bcm2835-isp/bcm2835-isp-ctrls.h
104 @@ -0,0 +1,67 @@
105 +/* SPDX-License-Identifier: GPL-2.0 */
106 +/*
107 + * Broadcom BCM2835 ISP driver
108 + *
109 + * Copyright © 2019-2020 Raspberry Pi (Trading) Ltd.
110 + *
111 + * Author: Naushir Patuck (naush@raspberrypi.com)
112 + *
113 + */
114 +
115 +#ifndef BCM2835_ISP_CTRLS
116 +#define BCM2835_ISP_CTRLS
117 +
118 +#include <linux/bcm2835-isp.h>
119 +
120 +struct bcm2835_isp_custom_ctrl {
121 + const char *name;
122 + u32 id;
123 + u32 size;
124 + u32 flags;
125 +};
126 +
127 +static const struct bcm2835_isp_custom_ctrl custom_ctrls[] = {
128 + {
129 + .name = "Colour Correction Matrix",
130 + .id = V4L2_CID_USER_BCM2835_ISP_CC_MATRIX,
131 + .size = sizeof(struct bcm2835_isp_custom_ccm),
132 + .flags = 0
133 + }, {
134 + .name = "Lens Shading",
135 + .id = V4L2_CID_USER_BCM2835_ISP_LENS_SHADING,
136 + .size = sizeof(struct bcm2835_isp_lens_shading),
137 + .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE
138 + }, {
139 + .name = "Black Level",
140 + .id = V4L2_CID_USER_BCM2835_ISP_BLACK_LEVEL,
141 + .size = sizeof(struct bcm2835_isp_black_level),
142 + .flags = 0
143 + }, {
144 + .name = "Green Equalisation",
145 + .id = V4L2_CID_USER_BCM2835_ISP_GEQ,
146 + .size = sizeof(struct bcm2835_isp_geq),
147 + .flags = 0
148 + }, {
149 + .name = "Gamma",
150 + .id = V4L2_CID_USER_BCM2835_ISP_GAMMA,
151 + .size = sizeof(struct bcm2835_isp_gamma),
152 + .flags = 0
153 + }, {
154 + .name = "Sharpen",
155 + .id = V4L2_CID_USER_BCM2835_ISP_SHARPEN,
156 + .size = sizeof(struct bcm2835_isp_sharpen),
157 + .flags = 0
158 + }, {
159 + .name = "Denoise",
160 + .id = V4L2_CID_USER_BCM2835_ISP_DENOISE,
161 + .size = sizeof(struct bcm2835_isp_denoise),
162 + .flags = 0
163 + }, {
164 + .name = "Defective Pixel Correction",
165 + .id = V4L2_CID_USER_BCM2835_ISP_DPC,
166 + .size = sizeof(struct bcm2835_isp_dpc),
167 + .flags = 0
168 + }
169 +};
170 +
171 +#endif
172 --- /dev/null
173 +++ b/drivers/staging/vc04_services/bcm2835-isp/bcm2835-isp-fmts.h
174 @@ -0,0 +1,353 @@
175 +/* SPDX-License-Identifier: GPL-2.0 */
176 +/*
177 + * Broadcom BCM2835 ISP driver
178 + *
179 + * Copyright © 2019-2020 Raspberry Pi (Trading) Ltd.
180 + *
181 + * Author: Naushir Patuck (naush@raspberrypi.com)
182 + *
183 + */
184 +
185 +#ifndef BCM2835_ISP_FMTS
186 +#define BCM2835_ISP_FMTS
187 +
188 +#include <linux/videodev2.h>
189 +#include "vchiq-mmal/mmal-encodings.h"
190 +
191 +struct bcm2835_isp_fmt {
192 + u32 fourcc;
193 + int depth;
194 + int bytesperline_align;
195 + u32 mmal_fmt;
196 + int size_multiplier_x2;
197 + enum v4l2_colorspace colorspace;
198 + unsigned int step_size;
199 +};
200 +
201 +static const struct bcm2835_isp_fmt supported_formats[] = {
202 + {
203 + /* YUV formats */
204 + .fourcc = V4L2_PIX_FMT_YUV420,
205 + .depth = 8,
206 + .bytesperline_align = 32,
207 + .mmal_fmt = MMAL_ENCODING_I420,
208 + .size_multiplier_x2 = 3,
209 + .colorspace = V4L2_COLORSPACE_SMPTE170M,
210 + .step_size = 2,
211 + }, {
212 + .fourcc = V4L2_PIX_FMT_YVU420,
213 + .depth = 8,
214 + .bytesperline_align = 32,
215 + .mmal_fmt = MMAL_ENCODING_YV12,
216 + .size_multiplier_x2 = 3,
217 + .colorspace = V4L2_COLORSPACE_SMPTE170M,
218 + .step_size = 2,
219 + }, {
220 + .fourcc = V4L2_PIX_FMT_NV12,
221 + .depth = 8,
222 + .bytesperline_align = 32,
223 + .mmal_fmt = MMAL_ENCODING_NV12,
224 + .size_multiplier_x2 = 3,
225 + .colorspace = V4L2_COLORSPACE_SMPTE170M,
226 + .step_size = 2,
227 + }, {
228 + .fourcc = V4L2_PIX_FMT_NV21,
229 + .depth = 8,
230 + .bytesperline_align = 32,
231 + .mmal_fmt = MMAL_ENCODING_NV21,
232 + .size_multiplier_x2 = 3,
233 + .colorspace = V4L2_COLORSPACE_SMPTE170M,
234 + .step_size = 2,
235 + }, {
236 + .fourcc = V4L2_PIX_FMT_YUYV,
237 + .depth = 16,
238 + .bytesperline_align = 64,
239 + .mmal_fmt = MMAL_ENCODING_YUYV,
240 + .size_multiplier_x2 = 2,
241 + .colorspace = V4L2_COLORSPACE_SMPTE170M,
242 + .step_size = 2,
243 + }, {
244 + .fourcc = V4L2_PIX_FMT_UYVY,
245 + .depth = 16,
246 + .bytesperline_align = 64,
247 + .mmal_fmt = MMAL_ENCODING_UYVY,
248 + .size_multiplier_x2 = 2,
249 + .colorspace = V4L2_COLORSPACE_SMPTE170M,
250 + .step_size = 2,
251 + }, {
252 + .fourcc = V4L2_PIX_FMT_YVYU,
253 + .depth = 16,
254 + .bytesperline_align = 64,
255 + .mmal_fmt = MMAL_ENCODING_YVYU,
256 + .size_multiplier_x2 = 2,
257 + .colorspace = V4L2_COLORSPACE_SMPTE170M,
258 + .step_size = 2,
259 + }, {
260 + .fourcc = V4L2_PIX_FMT_VYUY,
261 + .depth = 16,
262 + .bytesperline_align = 64,
263 + .mmal_fmt = MMAL_ENCODING_VYUY,
264 + .size_multiplier_x2 = 2,
265 + .colorspace = V4L2_COLORSPACE_SMPTE170M,
266 + .step_size = 2,
267 + }, {
268 + /* RGB formats */
269 + .fourcc = V4L2_PIX_FMT_RGB24,
270 + .depth = 24,
271 + .bytesperline_align = 32,
272 + .mmal_fmt = MMAL_ENCODING_RGB24,
273 + .size_multiplier_x2 = 2,
274 + .colorspace = V4L2_COLORSPACE_SRGB,
275 + .step_size = 1,
276 + }, {
277 + .fourcc = V4L2_PIX_FMT_RGB565,
278 + .depth = 16,
279 + .bytesperline_align = 32,
280 + .mmal_fmt = MMAL_ENCODING_RGB16,
281 + .size_multiplier_x2 = 2,
282 + .colorspace = V4L2_COLORSPACE_SRGB,
283 + .step_size = 1,
284 + }, {
285 + .fourcc = V4L2_PIX_FMT_BGR24,
286 + .depth = 24,
287 + .bytesperline_align = 32,
288 + .mmal_fmt = MMAL_ENCODING_BGR24,
289 + .size_multiplier_x2 = 2,
290 + .colorspace = V4L2_COLORSPACE_SRGB,
291 + .step_size = 1,
292 + }, {
293 + .fourcc = V4L2_PIX_FMT_XBGR32,
294 + .depth = 32,
295 + .bytesperline_align = 64,
296 + .mmal_fmt = MMAL_ENCODING_BGRA,
297 + .size_multiplier_x2 = 2,
298 + .colorspace = V4L2_COLORSPACE_SRGB,
299 + .step_size = 1,
300 + }, {
301 + .fourcc = V4L2_PIX_FMT_RGBX32,
302 + .depth = 32,
303 + .bytesperline_align = 64,
304 + .mmal_fmt = MMAL_ENCODING_RGBA,
305 + .size_multiplier_x2 = 2,
306 + .colorspace = V4L2_COLORSPACE_SRGB,
307 + .step_size = 1,
308 + }, {
309 + /* Bayer formats */
310 + /* 8 bit */
311 + .fourcc = V4L2_PIX_FMT_SRGGB8,
312 + .depth = 8,
313 + .bytesperline_align = 32,
314 + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB8,
315 + .size_multiplier_x2 = 2,
316 + .colorspace = V4L2_COLORSPACE_RAW,
317 + .step_size = 2,
318 + }, {
319 + .fourcc = V4L2_PIX_FMT_SBGGR8,
320 + .depth = 8,
321 + .bytesperline_align = 32,
322 + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR8,
323 + .size_multiplier_x2 = 2,
324 + .colorspace = V4L2_COLORSPACE_RAW,
325 + .step_size = 2,
326 + }, {
327 + .fourcc = V4L2_PIX_FMT_SGRBG8,
328 + .depth = 8,
329 + .bytesperline_align = 32,
330 + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG8,
331 + .size_multiplier_x2 = 2,
332 + .colorspace = V4L2_COLORSPACE_RAW,
333 + .step_size = 2,
334 + }, {
335 + .fourcc = V4L2_PIX_FMT_SGBRG8,
336 + .depth = 8,
337 + .bytesperline_align = 32,
338 + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG8,
339 + .size_multiplier_x2 = 2,
340 + .colorspace = V4L2_COLORSPACE_RAW,
341 + .step_size = 2,
342 + }, {
343 + /* 10 bit */
344 + .fourcc = V4L2_PIX_FMT_SRGGB10P,
345 + .depth = 10,
346 + .bytesperline_align = 32,
347 + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB10P,
348 + .size_multiplier_x2 = 2,
349 + .colorspace = V4L2_COLORSPACE_RAW,
350 + .step_size = 2,
351 + }, {
352 + .fourcc = V4L2_PIX_FMT_SBGGR10P,
353 + .depth = 10,
354 + .bytesperline_align = 32,
355 + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR10P,
356 + .size_multiplier_x2 = 2,
357 + .colorspace = V4L2_COLORSPACE_RAW,
358 + .step_size = 2,
359 + }, {
360 + .fourcc = V4L2_PIX_FMT_SGRBG10P,
361 + .depth = 10,
362 + .bytesperline_align = 32,
363 + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG10P,
364 + .size_multiplier_x2 = 2,
365 + .colorspace = V4L2_COLORSPACE_RAW,
366 + .step_size = 2,
367 + }, {
368 + .fourcc = V4L2_PIX_FMT_SGBRG10P,
369 + .depth = 10,
370 + .bytesperline_align = 32,
371 + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG10P,
372 + .size_multiplier_x2 = 2,
373 + .colorspace = V4L2_COLORSPACE_RAW,
374 + .step_size = 2,
375 + }, {
376 + /* 12 bit */
377 + .fourcc = V4L2_PIX_FMT_SRGGB12P,
378 + .depth = 12,
379 + .bytesperline_align = 32,
380 + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB12P,
381 + .size_multiplier_x2 = 2,
382 + .colorspace = V4L2_COLORSPACE_RAW,
383 + .step_size = 2,
384 + }, {
385 + .fourcc = V4L2_PIX_FMT_SBGGR12P,
386 + .depth = 12,
387 + .bytesperline_align = 32,
388 + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR12P,
389 + .size_multiplier_x2 = 2,
390 + .colorspace = V4L2_COLORSPACE_RAW,
391 + .step_size = 2,
392 + }, {
393 + .fourcc = V4L2_PIX_FMT_SGRBG12P,
394 + .depth = 12,
395 + .bytesperline_align = 32,
396 + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG12P,
397 + .size_multiplier_x2 = 2,
398 + .colorspace = V4L2_COLORSPACE_RAW,
399 + .step_size = 2,
400 + }, {
401 + .fourcc = V4L2_PIX_FMT_SGBRG12P,
402 + .depth = 12,
403 + .bytesperline_align = 32,
404 + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG12P,
405 + .size_multiplier_x2 = 2,
406 + .colorspace = V4L2_COLORSPACE_RAW,
407 + .step_size = 2,
408 + }, {
409 + /* 14 bit */
410 + .fourcc = V4L2_PIX_FMT_SRGGB14P,
411 + .depth = 14,
412 + .bytesperline_align = 32,
413 + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB14P,
414 + .size_multiplier_x2 = 2,
415 + .colorspace = V4L2_COLORSPACE_RAW,
416 + .step_size = 2,
417 + }, {
418 + .fourcc = V4L2_PIX_FMT_SBGGR14P,
419 + .depth = 14,
420 + .bytesperline_align = 32,
421 + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR14P,
422 + .size_multiplier_x2 = 2,
423 + .colorspace = V4L2_COLORSPACE_RAW,
424 + .step_size = 2,
425 + }, {
426 + .fourcc = V4L2_PIX_FMT_SGRBG14P,
427 + .depth = 14,
428 + .bytesperline_align = 32,
429 + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG14P,
430 + .size_multiplier_x2 = 2,
431 + .colorspace = V4L2_COLORSPACE_RAW,
432 + .step_size = 2,
433 + }, {
434 + .fourcc = V4L2_PIX_FMT_SGBRG14P,
435 + .depth = 14,
436 + .bytesperline_align = 32,
437 + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG14P,
438 + .size_multiplier_x2 = 2,
439 + .colorspace = V4L2_COLORSPACE_RAW,
440 + .step_size = 2,
441 + }, {
442 + /* 16 bit */
443 + .fourcc = V4L2_PIX_FMT_SRGGB16,
444 + .depth = 16,
445 + .bytesperline_align = 32,
446 + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB16,
447 + .size_multiplier_x2 = 2,
448 + .colorspace = V4L2_COLORSPACE_RAW,
449 + .step_size = 2,
450 + }, {
451 + .fourcc = V4L2_PIX_FMT_SBGGR16,
452 + .depth = 16,
453 + .bytesperline_align = 32,
454 + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR16,
455 + .size_multiplier_x2 = 2,
456 + .colorspace = V4L2_COLORSPACE_RAW,
457 + .step_size = 2,
458 + }, {
459 + .fourcc = V4L2_PIX_FMT_SGRBG16,
460 + .depth = 16,
461 + .bytesperline_align = 32,
462 + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG16,
463 + .size_multiplier_x2 = 2,
464 + .colorspace = V4L2_COLORSPACE_RAW,
465 + .step_size = 2,
466 + }, {
467 + .fourcc = V4L2_PIX_FMT_SGBRG16,
468 + .depth = 16,
469 + .bytesperline_align = 32,
470 + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG16,
471 + .size_multiplier_x2 = 2,
472 + .colorspace = V4L2_COLORSPACE_RAW,
473 + .step_size = 2,
474 + }, {
475 + /* Monochrome MIPI formats */
476 + /* 8 bit */
477 + .fourcc = V4L2_PIX_FMT_GREY,
478 + .depth = 8,
479 + .bytesperline_align = 32,
480 + .mmal_fmt = MMAL_ENCODING_GREY,
481 + .size_multiplier_x2 = 2,
482 + .colorspace = V4L2_COLORSPACE_RAW,
483 + .step_size = 2,
484 + }, {
485 + /* 10 bit */
486 + .fourcc = V4L2_PIX_FMT_Y10P,
487 + .depth = 10,
488 + .bytesperline_align = 32,
489 + .mmal_fmt = MMAL_ENCODING_Y10P,
490 + .size_multiplier_x2 = 2,
491 + .colorspace = V4L2_COLORSPACE_RAW,
492 + .step_size = 2,
493 + }, {
494 + /* 12 bit */
495 + .fourcc = V4L2_PIX_FMT_Y12P,
496 + .depth = 12,
497 + .bytesperline_align = 32,
498 + .mmal_fmt = MMAL_ENCODING_Y12P,
499 + .size_multiplier_x2 = 2,
500 + .colorspace = V4L2_COLORSPACE_RAW,
501 + .step_size = 2,
502 + }, {
503 + /* 14 bit */
504 + .fourcc = V4L2_PIX_FMT_Y14P,
505 + .depth = 14,
506 + .bytesperline_align = 32,
507 + .mmal_fmt = MMAL_ENCODING_Y14P,
508 + .size_multiplier_x2 = 2,
509 + .colorspace = V4L2_COLORSPACE_RAW,
510 + .step_size = 2,
511 + }, {
512 + /* 16 bit */
513 + .fourcc = V4L2_PIX_FMT_Y16,
514 + .depth = 16,
515 + .bytesperline_align = 32,
516 + .mmal_fmt = MMAL_ENCODING_Y16,
517 + .size_multiplier_x2 = 2,
518 + .colorspace = V4L2_COLORSPACE_RAW,
519 + .step_size = 2,
520 + }, {
521 + .fourcc = V4L2_META_FMT_BCM2835_ISP_STATS,
522 + .mmal_fmt = MMAL_ENCODING_BRCM_STATS,
523 + /* The rest are not valid fields for stats. */
524 + }
525 +};
526 +
527 +#endif
528 --- /dev/null
529 +++ b/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c
530 @@ -0,0 +1,1696 @@
531 +// SPDX-License-Identifier: GPL-2.0
532 +/*
533 + * Broadcom BCM2835 ISP driver
534 + *
535 + * Copyright © 2019-2020 Raspberry Pi (Trading) Ltd.
536 + *
537 + * Author: Naushir Patuck (naush@raspberrypi.com)
538 + *
539 + */
540 +
541 +#include <linux/module.h>
542 +#include <linux/platform_device.h>
543 +
544 +#include <media/v4l2-ctrls.h>
545 +#include <media/v4l2-device.h>
546 +#include <media/v4l2-event.h>
547 +#include <media/v4l2-ioctl.h>
548 +#include <media/videobuf2-dma-contig.h>
549 +
550 +#include "vchiq-mmal/mmal-msg.h"
551 +#include "vchiq-mmal/mmal-parameters.h"
552 +#include "vchiq-mmal/mmal-vchiq.h"
553 +
554 +#include "vc-sm-cma/vc_sm_knl.h"
555 +
556 +#include "bcm2835-isp-ctrls.h"
557 +#include "bcm2835-isp-fmts.h"
558 +
559 +MODULE_IMPORT_NS(DMA_BUF);
560 +
561 +static unsigned int debug;
562 +module_param(debug, uint, 0644);
563 +MODULE_PARM_DESC(debug, "activates debug info");
564 +
565 +static unsigned int video_nr = 13;
566 +module_param(video_nr, uint, 0644);
567 +MODULE_PARM_DESC(video_nr, "base video device number");
568 +
569 +#define BCM2835_ISP_NAME "bcm2835-isp"
570 +#define BCM2835_ISP_ENTITY_NAME_LEN 32
571 +
572 +#define BCM2835_ISP_NUM_OUTPUTS 1
573 +#define BCM2835_ISP_NUM_CAPTURES 2
574 +#define BCM2835_ISP_NUM_METADATA 1
575 +
576 +#define BCM2835_ISP_NUM_NODES \
577 + (BCM2835_ISP_NUM_OUTPUTS + BCM2835_ISP_NUM_CAPTURES + \
578 + BCM2835_ISP_NUM_METADATA)
579 +
580 +/* Default frame dimension of 1280 pixels. */
581 +#define DEFAULT_DIM 1280U
582 +/*
583 + * Maximum frame dimension of 16384 pixels. Even though the ISP runs in tiles,
584 + * have a sensible limit so that we do not create an excessive number of tiles
585 + * to process.
586 + */
587 +#define MAX_DIM 16384U
588 +/*
589 + * Minimum frame dimension of 64 pixels. Anything lower, and the tiling
590 + * algorithm may not be able to cope when applying filter context.
591 + */
592 +#define MIN_DIM 64U
593 +
594 +/* Timeout for stop_streaming to allow all buffers to return */
595 +#define COMPLETE_TIMEOUT (2 * HZ)
596 +
597 +/* Per-queue, driver-specific private data */
598 +struct bcm2835_isp_q_data {
599 + /*
600 + * These parameters should be treated as gospel, with everything else
601 + * being determined from them.
602 + */
603 + unsigned int bytesperline;
604 + unsigned int width;
605 + unsigned int height;
606 + unsigned int sizeimage;
607 + const struct bcm2835_isp_fmt *fmt;
608 +};
609 +
610 +/*
611 + * Structure to describe a single node /dev/video<N> which represents a single
612 + * input or output queue to the ISP device.
613 + */
614 +struct bcm2835_isp_node {
615 + int vfl_dir;
616 + unsigned int id;
617 + const char *name;
618 + struct vchiq_mmal_port *port;
619 + struct video_device vfd;
620 + struct media_pad pad;
621 + struct media_intf_devnode *intf_devnode;
622 + struct media_link *intf_link;
623 + struct mutex lock; /* top level device node lock */
624 + struct mutex queue_lock;
625 +
626 + struct vb2_queue queue;
627 + unsigned int sequence;
628 +
629 + /* The list of formats supported on the node. */
630 + struct bcm2835_isp_fmt const **supported_fmts;
631 + unsigned int num_supported_fmts;
632 +
633 + struct bcm2835_isp_q_data q_data;
634 +
635 + /* Parent device structure */
636 + struct bcm2835_isp_dev *dev;
637 +
638 + bool registered;
639 + bool media_node_registered;
640 +};
641 +
642 +/*
643 + * Structure representing the entire ISP device, comprising several input and
644 + * output nodes /dev/video<N>.
645 + */
646 +struct bcm2835_isp_dev {
647 + struct v4l2_device v4l2_dev;
648 + struct device *dev;
649 + struct v4l2_ctrl_handler ctrl_handler;
650 + struct media_device mdev;
651 + struct media_entity entity;
652 + bool media_device_registered;
653 + bool media_entity_registered;
654 + struct vchiq_mmal_instance *mmal_instance;
655 + struct vchiq_mmal_component *component;
656 + struct completion frame_cmplt;
657 +
658 + struct bcm2835_isp_node node[BCM2835_ISP_NUM_NODES];
659 + struct media_pad pad[BCM2835_ISP_NUM_NODES];
660 + atomic_t num_streaming;
661 +
662 + /* Image pipeline controls. */
663 + int r_gain;
664 + int b_gain;
665 +};
666 +
667 +struct bcm2835_isp_buffer {
668 + struct vb2_v4l2_buffer vb;
669 + struct mmal_buffer mmal;
670 +};
671 +
672 +static
673 +inline struct bcm2835_isp_dev *node_get_dev(struct bcm2835_isp_node *node)
674 +{
675 + return node->dev;
676 +}
677 +
678 +static inline bool node_is_output(struct bcm2835_isp_node *node)
679 +{
680 + return node->queue.type == V4L2_BUF_TYPE_VIDEO_OUTPUT;
681 +}
682 +
683 +static inline bool node_is_capture(struct bcm2835_isp_node *node)
684 +{
685 + return node->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE;
686 +}
687 +
688 +static inline bool node_is_stats(struct bcm2835_isp_node *node)
689 +{
690 + return node->queue.type == V4L2_BUF_TYPE_META_CAPTURE;
691 +}
692 +
693 +static inline enum v4l2_buf_type index_to_queue_type(int index)
694 +{
695 + if (index < BCM2835_ISP_NUM_OUTPUTS)
696 + return V4L2_BUF_TYPE_VIDEO_OUTPUT;
697 + else if (index < BCM2835_ISP_NUM_OUTPUTS + BCM2835_ISP_NUM_CAPTURES)
698 + return V4L2_BUF_TYPE_VIDEO_CAPTURE;
699 + else
700 + return V4L2_BUF_TYPE_META_CAPTURE;
701 +}
702 +
703 +static int set_isp_param(struct bcm2835_isp_node *node, u32 parameter,
704 + void *value, u32 value_size)
705 +{
706 + struct bcm2835_isp_dev *dev = node_get_dev(node);
707 +
708 + return vchiq_mmal_port_parameter_set(dev->mmal_instance, node->port,
709 + parameter, value, value_size);
710 +}
711 +
712 +static int set_wb_gains(struct bcm2835_isp_node *node)
713 +{
714 + struct bcm2835_isp_dev *dev = node_get_dev(node);
715 + struct mmal_parameter_awbgains gains = {
716 + .r_gain = { dev->r_gain, 1000 },
717 + .b_gain = { dev->b_gain, 1000 }
718 + };
719 +
720 + return set_isp_param(node, MMAL_PARAMETER_CUSTOM_AWB_GAINS,
721 + &gains, sizeof(gains));
722 +}
723 +
724 +static int set_digital_gain(struct bcm2835_isp_node *node, uint32_t gain)
725 +{
726 + struct s32_fract digital_gain = {
727 + .numerator = gain,
728 + .denominator = 1000
729 + };
730 +
731 + return set_isp_param(node, MMAL_PARAMETER_DIGITAL_GAIN,
732 + &digital_gain, sizeof(digital_gain));
733 +}
734 +
735 +static const struct bcm2835_isp_fmt *get_fmt(u32 mmal_fmt)
736 +{
737 + unsigned int i;
738 +
739 + for (i = 0; i < ARRAY_SIZE(supported_formats); i++) {
740 + if (supported_formats[i].mmal_fmt == mmal_fmt)
741 + return &supported_formats[i];
742 + }
743 + return NULL;
744 +}
745 +
746 +static const
747 +struct bcm2835_isp_fmt *find_format_by_fourcc(unsigned int fourcc,
748 + struct bcm2835_isp_node *node)
749 +{
750 + const struct bcm2835_isp_fmt *fmt;
751 + unsigned int i;
752 +
753 + for (i = 0; i < node->num_supported_fmts; i++) {
754 + fmt = node->supported_fmts[i];
755 + if (fmt->fourcc == fourcc)
756 + return fmt;
757 + }
758 +
759 + return NULL;
760 +}
761 +
762 +static const
763 +struct bcm2835_isp_fmt *find_format(struct v4l2_format *f,
764 + struct bcm2835_isp_node *node)
765 +{
766 + return find_format_by_fourcc(node_is_stats(node) ?
767 + f->fmt.meta.dataformat :
768 + f->fmt.pix.pixelformat,
769 + node);
770 +}
771 +
772 +/* vb2_to_mmal_buffer() - converts vb2 buffer header to MMAL
773 + *
774 + * Copies all the required fields from a VB2 buffer to the MMAL buffer header,
775 + * ready for sending to the VPU.
776 + */
777 +static void vb2_to_mmal_buffer(struct mmal_buffer *buf,
778 + struct vb2_v4l2_buffer *vb2)
779 +{
780 + u64 pts;
781 +
782 + buf->mmal_flags = 0;
783 + if (vb2->flags & V4L2_BUF_FLAG_KEYFRAME)
784 + buf->mmal_flags |= MMAL_BUFFER_HEADER_FLAG_KEYFRAME;
785 +
786 + /* Data must be framed correctly as one frame per buffer. */
787 + buf->mmal_flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END;
788 +
789 + buf->length = vb2->vb2_buf.planes[0].bytesused;
790 + /*
791 + * Minor ambiguity in the V4L2 spec as to whether passing in a 0 length
792 + * buffer, or one with V4L2_BUF_FLAG_LAST set denotes end of stream.
793 + * Handle either.
794 + */
795 + if (!buf->length || vb2->flags & V4L2_BUF_FLAG_LAST)
796 + buf->mmal_flags |= MMAL_BUFFER_HEADER_FLAG_EOS;
797 +
798 + /* vb2 timestamps in nsecs, mmal in usecs */
799 + pts = vb2->vb2_buf.timestamp;
800 + do_div(pts, 1000);
801 + buf->pts = pts;
802 + buf->dts = MMAL_TIME_UNKNOWN;
803 +}
804 +
805 +static void mmal_buffer_cb(struct vchiq_mmal_instance *instance,
806 + struct vchiq_mmal_port *port, int status,
807 + struct mmal_buffer *mmal_buf)
808 +{
809 + struct bcm2835_isp_buffer *q_buf;
810 + struct bcm2835_isp_node *node = port->cb_ctx;
811 + struct bcm2835_isp_dev *dev = node_get_dev(node);
812 + struct vb2_v4l2_buffer *vb2;
813 +
814 + q_buf = container_of(mmal_buf, struct bcm2835_isp_buffer, mmal);
815 + vb2 = &q_buf->vb;
816 + v4l2_dbg(2, debug, &dev->v4l2_dev,
817 + "%s: port:%s[%d], status:%d, buf:%p, dmabuf:%p, length:%lu, flags %u, pts %lld\n",
818 + __func__, node_is_output(node) ? "input" : "output", node->id,
819 + status, mmal_buf, mmal_buf->dma_buf, mmal_buf->length,
820 + mmal_buf->mmal_flags, mmal_buf->pts);
821 +
822 + if (mmal_buf->cmd)
823 + v4l2_err(&dev->v4l2_dev,
824 + "%s: Unexpected event on output callback - %08x\n",
825 + __func__, mmal_buf->cmd);
826 +
827 + if (status) {
828 + /* error in transfer */
829 + if (vb2) {
830 + /* there was a buffer with the error so return it */
831 + vb2_buffer_done(&vb2->vb2_buf, VB2_BUF_STATE_ERROR);
832 + }
833 + return;
834 + }
835 +
836 + /* vb2 timestamps in nsecs, mmal in usecs */
837 + vb2->vb2_buf.timestamp = mmal_buf->pts * 1000;
838 + vb2->sequence = node->sequence++;
839 + vb2_set_plane_payload(&vb2->vb2_buf, 0, mmal_buf->length);
840 + vb2_buffer_done(&vb2->vb2_buf, VB2_BUF_STATE_DONE);
841 +
842 + if (!port->enabled)
843 + complete(&dev->frame_cmplt);
844 +}
845 +
846 +static void setup_mmal_port_format(struct bcm2835_isp_node *node,
847 + struct vchiq_mmal_port *port)
848 +{
849 + struct bcm2835_isp_q_data *q_data = &node->q_data;
850 +
851 + port->format.encoding = q_data->fmt->mmal_fmt;
852 + /* Raw image format - set width/height */
853 + port->es.video.width = (q_data->bytesperline << 3) / q_data->fmt->depth;
854 + port->es.video.height = q_data->height;
855 + port->es.video.crop.width = q_data->width;
856 + port->es.video.crop.height = q_data->height;
857 + port->es.video.crop.x = 0;
858 + port->es.video.crop.y = 0;
859 +};
860 +
861 +static int setup_mmal_port(struct bcm2835_isp_node *node)
862 +{
863 + struct bcm2835_isp_dev *dev = node_get_dev(node);
864 + unsigned int enable = 1;
865 + int ret;
866 +
867 + v4l2_dbg(2, debug, &dev->v4l2_dev, "%s: setup %s[%d]\n", __func__,
868 + node->name, node->id);
869 +
870 + vchiq_mmal_port_parameter_set(dev->mmal_instance, node->port,
871 + MMAL_PARAMETER_ZERO_COPY, &enable,
872 + sizeof(enable));
873 + setup_mmal_port_format(node, node->port);
874 + ret = vchiq_mmal_port_set_format(dev->mmal_instance, node->port);
875 + if (ret < 0) {
876 + v4l2_dbg(1, debug, &dev->v4l2_dev,
877 + "%s: vchiq_mmal_port_set_format failed\n",
878 + __func__);
879 + return ret;
880 + }
881 +
882 + if (node->q_data.sizeimage < node->port->minimum_buffer.size) {
883 + v4l2_err(&dev->v4l2_dev,
884 + "buffer size mismatch sizeimage %u < min size %u\n",
885 + node->q_data.sizeimage,
886 + node->port->minimum_buffer.size);
887 + return -EINVAL;
888 + }
889 +
890 + return 0;
891 +}
892 +
893 +static int bcm2835_isp_mmal_buf_cleanup(struct mmal_buffer *mmal_buf)
894 +{
895 + mmal_vchi_buffer_cleanup(mmal_buf);
896 +
897 + if (mmal_buf->dma_buf) {
898 + dma_buf_put(mmal_buf->dma_buf);
899 + mmal_buf->dma_buf = NULL;
900 + }
901 +
902 + return 0;
903 +}
904 +
905 +static int bcm2835_isp_node_queue_setup(struct vb2_queue *q,
906 + unsigned int *nbuffers,
907 + unsigned int *nplanes,
908 + unsigned int sizes[],
909 + struct device *alloc_devs[])
910 +{
911 + struct bcm2835_isp_node *node = vb2_get_drv_priv(q);
912 + unsigned int size;
913 +
914 + if (setup_mmal_port(node))
915 + return -EINVAL;
916 +
917 + size = node->q_data.sizeimage;
918 + if (size == 0) {
919 + v4l2_info(&node_get_dev(node)->v4l2_dev,
920 + "%s: Image size unset in queue_setup for node %s[%d]\n",
921 + __func__, node->name, node->id);
922 + return -EINVAL;
923 + }
924 +
925 + if (*nplanes)
926 + return sizes[0] < size ? -EINVAL : 0;
927 +
928 + *nplanes = 1;
929 + sizes[0] = size;
930 +
931 + node->port->current_buffer.size = size;
932 +
933 + if (*nbuffers < node->port->minimum_buffer.num)
934 + *nbuffers = node->port->minimum_buffer.num;
935 +
936 + node->port->current_buffer.num = *nbuffers;
937 +
938 + v4l2_dbg(2, debug, &node_get_dev(node)->v4l2_dev,
939 + "%s: Image size %u, nbuffers %u for node %s[%d]\n",
940 + __func__, sizes[0], *nbuffers, node->name, node->id);
941 + return 0;
942 +}
943 +
944 +static int bcm2835_isp_buf_init(struct vb2_buffer *vb)
945 +{
946 + struct bcm2835_isp_node *node = vb2_get_drv_priv(vb->vb2_queue);
947 + struct bcm2835_isp_dev *dev = node_get_dev(node);
948 + struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
949 + struct bcm2835_isp_buffer *buf =
950 + container_of(vb2, struct bcm2835_isp_buffer, vb);
951 +
952 + v4l2_dbg(3, debug, &dev->v4l2_dev, "%s: vb %p\n", __func__, vb);
953 +
954 + buf->mmal.buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
955 + buf->mmal.buffer_size = vb2_plane_size(&buf->vb.vb2_buf, 0);
956 + mmal_vchi_buffer_init(dev->mmal_instance, &buf->mmal);
957 + return 0;
958 +}
959 +
960 +static int bcm2835_isp_buf_prepare(struct vb2_buffer *vb)
961 +{
962 + struct bcm2835_isp_node *node = vb2_get_drv_priv(vb->vb2_queue);
963 + struct bcm2835_isp_dev *dev = node_get_dev(node);
964 + struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
965 + struct bcm2835_isp_buffer *buf =
966 + container_of(vb2, struct bcm2835_isp_buffer, vb);
967 + struct dma_buf *dma_buf;
968 + int ret;
969 +
970 + v4l2_dbg(3, debug, &dev->v4l2_dev, "%s: type: %d ptr %p\n",
971 + __func__, vb->vb2_queue->type, vb);
972 +
973 + if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
974 + if (vb2->field == V4L2_FIELD_ANY)
975 + vb2->field = V4L2_FIELD_NONE;
976 + if (vb2->field != V4L2_FIELD_NONE) {
977 + v4l2_err(&dev->v4l2_dev,
978 + "%s field isn't supported\n", __func__);
979 + return -EINVAL;
980 + }
981 + }
982 +
983 + if (vb2_plane_size(vb, 0) < node->q_data.sizeimage) {
984 + v4l2_err(&dev->v4l2_dev,
985 + "%s data will not fit into plane (%lu < %lu)\n",
986 + __func__, vb2_plane_size(vb, 0),
987 + (long)node->q_data.sizeimage);
988 + return -EINVAL;
989 + }
990 +
991 + if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type))
992 + vb2_set_plane_payload(vb, 0, node->q_data.sizeimage);
993 +
994 + switch (vb->memory) {
995 + case VB2_MEMORY_DMABUF:
996 + dma_buf = dma_buf_get(vb->planes[0].m.fd);
997 +
998 + if (dma_buf != buf->mmal.dma_buf) {
999 + /*
1000 + * dmabuf either hasn't already been mapped, or it has
1001 + * changed.
1002 + */
1003 + if (buf->mmal.dma_buf) {
1004 + v4l2_err(&dev->v4l2_dev,
1005 + "%s Buffer changed - why did the core not call cleanup?\n",
1006 + __func__);
1007 + bcm2835_isp_mmal_buf_cleanup(&buf->mmal);
1008 + }
1009 +
1010 + buf->mmal.dma_buf = dma_buf;
1011 + } else {
1012 + /*
1013 + * Already have a reference to the buffer, so release it
1014 + * here.
1015 + */
1016 + dma_buf_put(dma_buf);
1017 + }
1018 + ret = 0;
1019 + break;
1020 + case VB2_MEMORY_MMAP:
1021 + /*
1022 + * We want to do this at init, but vb2_core_expbuf checks that
1023 + * the index < q->num_buffers, and q->num_buffers only gets
1024 + * updated once all the buffers are allocated.
1025 + */
1026 + if (!buf->mmal.dma_buf) {
1027 + ret = vb2_core_expbuf_dmabuf(vb->vb2_queue,
1028 + vb->vb2_queue->type,
1029 + vb->index, 0, O_CLOEXEC,
1030 + &buf->mmal.dma_buf);
1031 + v4l2_dbg(3, debug, &dev->v4l2_dev,
1032 + "%s: exporting ptr %p to dmabuf %p\n",
1033 + __func__, vb, buf->mmal.dma_buf);
1034 + if (ret)
1035 + v4l2_err(&dev->v4l2_dev,
1036 + "%s: Failed to expbuf idx %d, ret %d\n",
1037 + __func__, vb->index, ret);
1038 + } else {
1039 + ret = 0;
1040 + }
1041 + break;
1042 + default:
1043 + ret = -EINVAL;
1044 + break;
1045 + }
1046 +
1047 + return ret;
1048 +}
1049 +
1050 +static void bcm2835_isp_node_buffer_queue(struct vb2_buffer *buf)
1051 +{
1052 + struct bcm2835_isp_node *node = vb2_get_drv_priv(buf->vb2_queue);
1053 + struct vb2_v4l2_buffer *vbuf =
1054 + container_of(buf, struct vb2_v4l2_buffer, vb2_buf);
1055 + struct bcm2835_isp_buffer *buffer =
1056 + container_of(vbuf, struct bcm2835_isp_buffer, vb);
1057 + struct bcm2835_isp_dev *dev = node_get_dev(node);
1058 +
1059 + v4l2_dbg(3, debug, &dev->v4l2_dev, "%s: node %s[%d], buffer %p\n",
1060 + __func__, node->name, node->id, buffer);
1061 +
1062 + vb2_to_mmal_buffer(&buffer->mmal, &buffer->vb);
1063 + v4l2_dbg(3, debug, &dev->v4l2_dev,
1064 + "%s: node %s[%d] - submitting mmal dmabuf %p\n", __func__,
1065 + node->name, node->id, buffer->mmal.dma_buf);
1066 + vchiq_mmal_submit_buffer(dev->mmal_instance, node->port, &buffer->mmal);
1067 +}
1068 +
1069 +static void bcm2835_isp_buffer_cleanup(struct vb2_buffer *vb)
1070 +{
1071 + struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
1072 + struct bcm2835_isp_buffer *buffer =
1073 + container_of(vb2, struct bcm2835_isp_buffer, vb);
1074 +
1075 + bcm2835_isp_mmal_buf_cleanup(&buffer->mmal);
1076 +}
1077 +
1078 +static int bcm2835_isp_node_start_streaming(struct vb2_queue *q,
1079 + unsigned int count)
1080 +{
1081 + struct bcm2835_isp_node *node = vb2_get_drv_priv(q);
1082 + struct bcm2835_isp_dev *dev = node_get_dev(node);
1083 + int ret;
1084 +
1085 + v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: node %s[%d] (count %u)\n",
1086 + __func__, node->name, node->id, count);
1087 +
1088 + ret = vchiq_mmal_component_enable(dev->mmal_instance, dev->component);
1089 + if (ret) {
1090 + v4l2_err(&dev->v4l2_dev, "%s: Failed enabling component, ret %d\n",
1091 + __func__, ret);
1092 + return -EIO;
1093 + }
1094 +
1095 + node->sequence = 0;
1096 + node->port->cb_ctx = node;
1097 + ret = vchiq_mmal_port_enable(dev->mmal_instance, node->port,
1098 + mmal_buffer_cb);
1099 + if (!ret)
1100 + atomic_inc(&dev->num_streaming);
1101 + else
1102 + v4l2_err(&dev->v4l2_dev,
1103 + "%s: Failed enabling port, ret %d\n", __func__, ret);
1104 +
1105 + return ret;
1106 +}
1107 +
1108 +static void bcm2835_isp_node_stop_streaming(struct vb2_queue *q)
1109 +{
1110 + struct bcm2835_isp_node *node = vb2_get_drv_priv(q);
1111 + struct bcm2835_isp_dev *dev = node_get_dev(node);
1112 + unsigned int i;
1113 + int ret;
1114 +
1115 + v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: node %s[%d], mmal port %p\n",
1116 + __func__, node->name, node->id, node->port);
1117 +
1118 + init_completion(&dev->frame_cmplt);
1119 +
1120 + /* Disable MMAL port - this will flush buffers back */
1121 + ret = vchiq_mmal_port_disable(dev->mmal_instance, node->port);
1122 + if (ret)
1123 + v4l2_err(&dev->v4l2_dev,
1124 + "%s: Failed disabling %s port, ret %d\n", __func__,
1125 + node_is_output(node) ? "i/p" : "o/p",
1126 + ret);
1127 +
1128 + while (atomic_read(&node->port->buffers_with_vpu)) {
1129 + v4l2_dbg(1, debug, &dev->v4l2_dev,
1130 + "%s: Waiting for buffers to be returned - %d outstanding\n",
1131 + __func__, atomic_read(&node->port->buffers_with_vpu));
1132 + ret = wait_for_completion_timeout(&dev->frame_cmplt,
1133 + COMPLETE_TIMEOUT);
1134 + if (ret <= 0) {
1135 + v4l2_err(&dev->v4l2_dev,
1136 + "%s: Timeout waiting for buffers to be returned - %d outstanding\n",
1137 + __func__,
1138 + atomic_read(&node->port->buffers_with_vpu));
1139 + break;
1140 + }
1141 + }
1142 +
1143 + /* Release the VCSM handle here to release the associated dmabuf */
1144 + for (i = 0; i < q->num_buffers; i++) {
1145 + struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(q->bufs[i]);
1146 + struct bcm2835_isp_buffer *buf =
1147 + container_of(vb2, struct bcm2835_isp_buffer, vb);
1148 + bcm2835_isp_mmal_buf_cleanup(&buf->mmal);
1149 + }
1150 +
1151 + atomic_dec(&dev->num_streaming);
1152 + /* If all ports disabled, then disable the component */
1153 + if (atomic_read(&dev->num_streaming) == 0) {
1154 + ret = vchiq_mmal_component_disable(dev->mmal_instance,
1155 + dev->component);
1156 + if (ret) {
1157 + v4l2_err(&dev->v4l2_dev,
1158 + "%s: Failed disabling component, ret %d\n",
1159 + __func__, ret);
1160 + }
1161 + }
1162 +
1163 + /*
1164 + * Simply wait for any vb2 buffers to finish. We could take steps to
1165 + * make them complete more quickly if we care, or even return them
1166 + * ourselves.
1167 + */
1168 + vb2_wait_for_all_buffers(&node->queue);
1169 +}
1170 +
1171 +static const struct vb2_ops bcm2835_isp_node_queue_ops = {
1172 + .queue_setup = bcm2835_isp_node_queue_setup,
1173 + .buf_init = bcm2835_isp_buf_init,
1174 + .buf_prepare = bcm2835_isp_buf_prepare,
1175 + .buf_queue = bcm2835_isp_node_buffer_queue,
1176 + .buf_cleanup = bcm2835_isp_buffer_cleanup,
1177 + .start_streaming = bcm2835_isp_node_start_streaming,
1178 + .stop_streaming = bcm2835_isp_node_stop_streaming,
1179 +};
1180 +
1181 +static const
1182 +struct bcm2835_isp_fmt *get_default_format(struct bcm2835_isp_node *node)
1183 +{
1184 + return node->supported_fmts[0];
1185 +}
1186 +
1187 +static inline unsigned int get_bytesperline(int width,
1188 + const struct bcm2835_isp_fmt *fmt)
1189 +{
1190 + /* GPU aligns 24bpp images to a multiple of 32 pixels (not bytes). */
1191 + if (fmt->depth == 24)
1192 + return ALIGN(width, 32) * 3;
1193 + else
1194 + return ALIGN((width * fmt->depth) >> 3, fmt->bytesperline_align);
1195 +}
1196 +
1197 +static inline unsigned int get_sizeimage(int bpl, int width, int height,
1198 + const struct bcm2835_isp_fmt *fmt)
1199 +{
1200 + return (bpl * height * fmt->size_multiplier_x2) >> 1;
1201 +}
1202 +
1203 +static int bcm2835_isp_s_ctrl(struct v4l2_ctrl *ctrl)
1204 +{
1205 + struct bcm2835_isp_dev *dev =
1206 + container_of(ctrl->handler, struct bcm2835_isp_dev, ctrl_handler);
1207 + struct bcm2835_isp_node *node = &dev->node[0];
1208 + int ret = 0;
1209 +
1210 + /*
1211 + * The ISP firmware driver will ensure these settings are applied on
1212 + * a frame boundary, so we are safe to write them as they come in.
1213 + *
1214 + * Note that the bcm2835_isp_* param structures are identical to the
1215 + * mmal-parameters.h definitions. This avoids the need for unnecessary
1216 + * field-by-field copying between structures.
1217 + */
1218 + switch (ctrl->id) {
1219 + case V4L2_CID_RED_BALANCE:
1220 + dev->r_gain = ctrl->val;
1221 + ret = set_wb_gains(node);
1222 + break;
1223 + case V4L2_CID_BLUE_BALANCE:
1224 + dev->b_gain = ctrl->val;
1225 + ret = set_wb_gains(node);
1226 + break;
1227 + case V4L2_CID_DIGITAL_GAIN:
1228 + ret = set_digital_gain(node, ctrl->val);
1229 + break;
1230 + case V4L2_CID_USER_BCM2835_ISP_CC_MATRIX:
1231 + ret = set_isp_param(node, MMAL_PARAMETER_CUSTOM_CCM,
1232 + ctrl->p_new.p_u8,
1233 + sizeof(struct bcm2835_isp_custom_ccm));
1234 + break;
1235 + case V4L2_CID_USER_BCM2835_ISP_LENS_SHADING:
1236 + {
1237 + struct bcm2835_isp_lens_shading *v4l2_ls;
1238 + struct mmal_parameter_lens_shading_v2 ls;
1239 + struct dma_buf *dmabuf;
1240 + void *vcsm_handle;
1241 +
1242 + v4l2_ls = (struct bcm2835_isp_lens_shading *)ctrl->p_new.p_u8;
1243 + /*
1244 + * struct bcm2835_isp_lens_shading and struct
1245 + * mmal_parameter_lens_shading_v2 match so that we can do a
1246 + * simple memcpy here.
1247 + * Only the dmabuf to the actual table needs any manipulation.
1248 + */
1249 + memcpy(&ls, v4l2_ls, sizeof(ls));
1250 +
1251 + dmabuf = dma_buf_get(v4l2_ls->dmabuf);
1252 + if (IS_ERR_OR_NULL(dmabuf))
1253 + return -EINVAL;
1254 +
1255 + ret = vc_sm_cma_import_dmabuf(dmabuf, &vcsm_handle);
1256 + if (ret) {
1257 + dma_buf_put(dmabuf);
1258 + return -EINVAL;
1259 + }
1260 +
1261 + ls.mem_handle_table = vc_sm_cma_int_handle(vcsm_handle);
1262 + if (ls.mem_handle_table)
1263 + /* The VPU will take a reference on the vcsm handle,
1264 + * which in turn will retain a reference on the dmabuf.
1265 + * This code can therefore safely release all
1266 + * references to the buffer.
1267 + */
1268 + ret = set_isp_param(node,
1269 + MMAL_PARAMETER_LENS_SHADING_OVERRIDE,
1270 + &ls,
1271 + sizeof(ls));
1272 + else
1273 + ret = -EINVAL;
1274 +
1275 + vc_sm_cma_free(vcsm_handle);
1276 + dma_buf_put(dmabuf);
1277 + break;
1278 + }
1279 + case V4L2_CID_USER_BCM2835_ISP_BLACK_LEVEL:
1280 + ret = set_isp_param(node, MMAL_PARAMETER_BLACK_LEVEL,
1281 + ctrl->p_new.p_u8,
1282 + sizeof(struct bcm2835_isp_black_level));
1283 + break;
1284 + case V4L2_CID_USER_BCM2835_ISP_GEQ:
1285 + ret = set_isp_param(node, MMAL_PARAMETER_GEQ,
1286 + ctrl->p_new.p_u8,
1287 + sizeof(struct bcm2835_isp_geq));
1288 + break;
1289 + case V4L2_CID_USER_BCM2835_ISP_GAMMA:
1290 + ret = set_isp_param(node, MMAL_PARAMETER_GAMMA,
1291 + ctrl->p_new.p_u8,
1292 + sizeof(struct bcm2835_isp_gamma));
1293 + break;
1294 + case V4L2_CID_USER_BCM2835_ISP_DENOISE:
1295 + ret = set_isp_param(node, MMAL_PARAMETER_DENOISE,
1296 + ctrl->p_new.p_u8,
1297 + sizeof(struct bcm2835_isp_denoise));
1298 + break;
1299 + case V4L2_CID_USER_BCM2835_ISP_SHARPEN:
1300 + ret = set_isp_param(node, MMAL_PARAMETER_SHARPEN,
1301 + ctrl->p_new.p_u8,
1302 + sizeof(struct bcm2835_isp_sharpen));
1303 + break;
1304 + case V4L2_CID_USER_BCM2835_ISP_DPC:
1305 + ret = set_isp_param(node, MMAL_PARAMETER_DPC,
1306 + ctrl->p_new.p_u8,
1307 + sizeof(struct bcm2835_isp_dpc));
1308 + break;
1309 + default:
1310 + v4l2_info(&dev->v4l2_dev, "Unrecognised control\n");
1311 + ret = -EINVAL;
1312 + }
1313 +
1314 + if (ret) {
1315 + v4l2_err(&dev->v4l2_dev, "%s: Failed setting ctrl \"%s\" (%08x), err %d\n",
1316 + __func__, ctrl->name, ctrl->id, ret);
1317 + ret = -EIO;
1318 + }
1319 +
1320 + return ret;
1321 +}
1322 +
1323 +static const struct v4l2_ctrl_ops bcm2835_isp_ctrl_ops = {
1324 + .s_ctrl = bcm2835_isp_s_ctrl,
1325 +};
1326 +
1327 +static const struct v4l2_file_operations bcm2835_isp_fops = {
1328 + .owner = THIS_MODULE,
1329 + .open = v4l2_fh_open,
1330 + .release = vb2_fop_release,
1331 + .poll = vb2_fop_poll,
1332 + .unlocked_ioctl = video_ioctl2,
1333 + .mmap = vb2_fop_mmap
1334 +};
1335 +
1336 +static int populate_qdata_fmt(struct v4l2_format *f,
1337 + struct bcm2835_isp_node *node)
1338 +{
1339 + struct bcm2835_isp_dev *dev = node_get_dev(node);
1340 + struct bcm2835_isp_q_data *q_data = &node->q_data;
1341 + int ret;
1342 +
1343 + if (!node_is_stats(node)) {
1344 + v4l2_dbg(1, debug, &dev->v4l2_dev,
1345 + "%s: Setting pix format for type %d, wxh: %ux%u, fmt: %08x, size %u\n",
1346 + __func__, f->type, f->fmt.pix.width, f->fmt.pix.height,
1347 + f->fmt.pix.pixelformat, f->fmt.pix.sizeimage);
1348 +
1349 + q_data->fmt = find_format(f, node);
1350 + q_data->width = f->fmt.pix.width;
1351 + q_data->height = f->fmt.pix.height;
1352 + q_data->height = f->fmt.pix.height;
1353 +
1354 + /* All parameters should have been set correctly by try_fmt */
1355 + q_data->bytesperline = f->fmt.pix.bytesperline;
1356 + q_data->sizeimage = f->fmt.pix.sizeimage;
1357 + } else {
1358 + v4l2_dbg(1, debug, &dev->v4l2_dev,
1359 + "%s: Setting meta format for fmt: %08x, size %u\n",
1360 + __func__, f->fmt.meta.dataformat,
1361 + f->fmt.meta.buffersize);
1362 +
1363 + q_data->fmt = find_format(f, node);
1364 + q_data->width = 0;
1365 + q_data->height = 0;
1366 + q_data->bytesperline = 0;
1367 + q_data->sizeimage = f->fmt.meta.buffersize;
1368 + }
1369 +
1370 + v4l2_dbg(1, debug, &dev->v4l2_dev,
1371 + "%s: Calculated bpl as %u, size %u\n", __func__,
1372 + q_data->bytesperline, q_data->sizeimage);
1373 +
1374 + setup_mmal_port_format(node, node->port);
1375 + ret = vchiq_mmal_port_set_format(dev->mmal_instance, node->port);
1376 + if (ret) {
1377 + v4l2_err(&dev->v4l2_dev,
1378 + "%s: Failed vchiq_mmal_port_set_format on port, ret %d\n",
1379 + __func__, ret);
1380 + ret = -EINVAL;
1381 + }
1382 +
1383 + if (q_data->sizeimage < node->port->minimum_buffer.size) {
1384 + v4l2_err(&dev->v4l2_dev,
1385 + "%s: Current buffer size of %u < min buf size %u - driver mismatch to MMAL\n",
1386 + __func__,
1387 + q_data->sizeimage,
1388 + node->port->minimum_buffer.size);
1389 + }
1390 +
1391 + v4l2_dbg(1, debug, &dev->v4l2_dev,
1392 + "%s: Set format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
1393 + __func__, f->type, q_data->width, q_data->height,
1394 + q_data->fmt->fourcc, q_data->sizeimage);
1395 +
1396 + return ret;
1397 +}
1398 +
1399 +static int bcm2835_isp_node_querycap(struct file *file, void *priv,
1400 + struct v4l2_capability *cap)
1401 +{
1402 + strscpy(cap->driver, BCM2835_ISP_NAME, sizeof(cap->driver));
1403 + strscpy(cap->card, BCM2835_ISP_NAME, sizeof(cap->card));
1404 + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
1405 + BCM2835_ISP_NAME);
1406 +
1407 + return 0;
1408 +}
1409 +
1410 +static int bcm2835_isp_node_g_fmt(struct file *file, void *priv,
1411 + struct v4l2_format *f)
1412 +{
1413 + struct bcm2835_isp_node *node = video_drvdata(file);
1414 +
1415 + if (f->type != node->queue.type)
1416 + return -EINVAL;
1417 +
1418 + if (node_is_stats(node)) {
1419 + f->fmt.meta.dataformat = V4L2_META_FMT_BCM2835_ISP_STATS;
1420 + f->fmt.meta.buffersize =
1421 + node->port->minimum_buffer.size;
1422 + } else {
1423 + struct bcm2835_isp_q_data *q_data = &node->q_data;
1424 +
1425 + f->fmt.pix.width = q_data->width;
1426 + f->fmt.pix.height = q_data->height;
1427 + f->fmt.pix.field = V4L2_FIELD_NONE;
1428 + f->fmt.pix.pixelformat = q_data->fmt->fourcc;
1429 + f->fmt.pix.bytesperline = q_data->bytesperline;
1430 + f->fmt.pix.sizeimage = q_data->sizeimage;
1431 + f->fmt.pix.colorspace = q_data->fmt->colorspace;
1432 + }
1433 +
1434 + return 0;
1435 +}
1436 +
1437 +static int bcm2835_isp_node_enum_fmt(struct file *file, void *priv,
1438 + struct v4l2_fmtdesc *f)
1439 +{
1440 + struct bcm2835_isp_node *node = video_drvdata(file);
1441 +
1442 + if (f->type != node->queue.type)
1443 + return -EINVAL;
1444 +
1445 + if (f->index < node->num_supported_fmts) {
1446 + /* Format found */
1447 + f->pixelformat = node->supported_fmts[f->index]->fourcc;
1448 + f->flags = 0;
1449 + return 0;
1450 + }
1451 +
1452 + return -EINVAL;
1453 +}
1454 +
1455 +static int bcm2835_isp_enum_framesizes(struct file *file, void *priv,
1456 + struct v4l2_frmsizeenum *fsize)
1457 +{
1458 + struct bcm2835_isp_node *node = video_drvdata(file);
1459 + struct bcm2835_isp_dev *dev = node_get_dev(node);
1460 + const struct bcm2835_isp_fmt *fmt;
1461 +
1462 + if (node_is_stats(node) || fsize->index)
1463 + return -EINVAL;
1464 +
1465 + fmt = find_format_by_fourcc(fsize->pixel_format, node);
1466 + if (!fmt) {
1467 + v4l2_err(&dev->v4l2_dev, "Invalid pixel code: %x\n",
1468 + fsize->pixel_format);
1469 + return -EINVAL;
1470 + }
1471 +
1472 + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
1473 + fsize->stepwise.min_width = MIN_DIM;
1474 + fsize->stepwise.max_width = MAX_DIM;
1475 + fsize->stepwise.step_width = fmt->step_size;
1476 +
1477 + fsize->stepwise.min_height = MIN_DIM;
1478 + fsize->stepwise.max_height = MAX_DIM;
1479 + fsize->stepwise.step_height = fmt->step_size;
1480 +
1481 + return 0;
1482 +}
1483 +
1484 +static int bcm2835_isp_node_try_fmt(struct file *file, void *priv,
1485 + struct v4l2_format *f)
1486 +{
1487 + struct bcm2835_isp_node *node = video_drvdata(file);
1488 + const struct bcm2835_isp_fmt *fmt;
1489 +
1490 + if (f->type != node->queue.type)
1491 + return -EINVAL;
1492 +
1493 + fmt = find_format(f, node);
1494 + if (!fmt)
1495 + fmt = get_default_format(node);
1496 +
1497 + if (!node_is_stats(node)) {
1498 + f->fmt.pix.width = max(min(f->fmt.pix.width, MAX_DIM),
1499 + MIN_DIM);
1500 + f->fmt.pix.height = max(min(f->fmt.pix.height, MAX_DIM),
1501 + MIN_DIM);
1502 +
1503 + f->fmt.pix.pixelformat = fmt->fourcc;
1504 + f->fmt.pix.colorspace = fmt->colorspace;
1505 + f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width,
1506 + fmt);
1507 + f->fmt.pix.field = V4L2_FIELD_NONE;
1508 + f->fmt.pix.sizeimage =
1509 + get_sizeimage(f->fmt.pix.bytesperline, f->fmt.pix.width,
1510 + f->fmt.pix.height, fmt);
1511 + } else {
1512 + f->fmt.meta.dataformat = fmt->fourcc;
1513 + f->fmt.meta.buffersize = node->port->minimum_buffer.size;
1514 + }
1515 +
1516 + return 0;
1517 +}
1518 +
1519 +static int bcm2835_isp_node_s_fmt(struct file *file, void *priv,
1520 + struct v4l2_format *f)
1521 +{
1522 + struct bcm2835_isp_node *node = video_drvdata(file);
1523 + int ret;
1524 +
1525 + if (f->type != node->queue.type)
1526 + return -EINVAL;
1527 +
1528 + ret = bcm2835_isp_node_try_fmt(file, priv, f);
1529 + if (ret)
1530 + return ret;
1531 +
1532 + v4l2_dbg(1, debug, &node_get_dev(node)->v4l2_dev,
1533 + "%s: Set format for node %s[%d]\n",
1534 + __func__, node->name, node->id);
1535 +
1536 + return populate_qdata_fmt(f, node);
1537 +}
1538 +
1539 +static int bcm2835_isp_node_s_selection(struct file *file, void *fh,
1540 + struct v4l2_selection *s)
1541 +{
1542 + struct mmal_parameter_crop crop;
1543 + struct bcm2835_isp_node *node = video_drvdata(file);
1544 + struct bcm2835_isp_dev *dev = node_get_dev(node);
1545 +
1546 + /* This return value is required fro V4L2 compliance. */
1547 + if (node_is_stats(node))
1548 + return -ENOTTY;
1549 +
1550 + if (!s->r.width || !s->r.height)
1551 + return -EINVAL;
1552 +
1553 + /* We can only set crop on the input. */
1554 + switch (s->target) {
1555 + case V4L2_SEL_TGT_CROP:
1556 + /*
1557 + * Adjust the crop window if it goes outside of the frame
1558 + * dimensions.
1559 + */
1560 + s->r.left = min((unsigned int)max(s->r.left, 0),
1561 + node->q_data.width - MIN_DIM);
1562 + s->r.top = min((unsigned int)max(s->r.top, 0),
1563 + node->q_data.height - MIN_DIM);
1564 + s->r.width = max(min(s->r.width,
1565 + node->q_data.width - s->r.left), MIN_DIM);
1566 + s->r.height = max(min(s->r.height,
1567 + node->q_data.height - s->r.top), MIN_DIM);
1568 + break;
1569 + case V4L2_SEL_TGT_CROP_DEFAULT:
1570 + /* Default (i.e. no) crop window. */
1571 + s->r.left = 0;
1572 + s->r.top = 0;
1573 + s->r.width = node->q_data.width;
1574 + s->r.height = node->q_data.height;
1575 + break;
1576 + default:
1577 + return -EINVAL;
1578 + }
1579 +
1580 + crop.rect.x = s->r.left;
1581 + crop.rect.y = s->r.top;
1582 + crop.rect.width = s->r.width;
1583 + crop.rect.height = s->r.height;
1584 +
1585 + return vchiq_mmal_port_parameter_set(dev->mmal_instance, node->port,
1586 + MMAL_PARAMETER_CROP,
1587 + &crop, sizeof(crop));
1588 +}
1589 +
1590 +static int bcm2835_isp_node_g_selection(struct file *file, void *fh,
1591 + struct v4l2_selection *s)
1592 +{
1593 + struct mmal_parameter_crop crop;
1594 + struct bcm2835_isp_node *node = video_drvdata(file);
1595 + struct bcm2835_isp_dev *dev = node_get_dev(node);
1596 + u32 crop_size = sizeof(crop);
1597 + int ret;
1598 +
1599 + /* We can only return out an input crop. */
1600 + switch (s->target) {
1601 + case V4L2_SEL_TGT_CROP:
1602 + ret = vchiq_mmal_port_parameter_get(dev->mmal_instance,
1603 + node->port,
1604 + MMAL_PARAMETER_CROP,
1605 + &crop, &crop_size);
1606 + if (!ret) {
1607 + s->r.left = crop.rect.x;
1608 + s->r.top = crop.rect.y;
1609 + s->r.width = crop.rect.width;
1610 + s->r.height = crop.rect.height;
1611 + }
1612 + break;
1613 + case V4L2_SEL_TGT_CROP_DEFAULT:
1614 + case V4L2_SEL_TGT_CROP_BOUNDS:
1615 + /* Default (i.e. no) crop window. */
1616 + s->r.left = 0;
1617 + s->r.top = 0;
1618 + s->r.width = node->q_data.width;
1619 + s->r.height = node->q_data.height;
1620 + ret = 0;
1621 + break;
1622 + default:
1623 + ret = -EINVAL;
1624 + }
1625 +
1626 + return ret;
1627 +}
1628 +
1629 +static int bcm3285_isp_subscribe_event(struct v4l2_fh *fh,
1630 + const struct v4l2_event_subscription *s)
1631 +{
1632 + switch (s->type) {
1633 + /* Cannot change source parameters dynamically at runtime. */
1634 + case V4L2_EVENT_SOURCE_CHANGE:
1635 + return -EINVAL;
1636 + case V4L2_EVENT_CTRL:
1637 + return v4l2_ctrl_subscribe_event(fh, s);
1638 + default:
1639 + return v4l2_event_subscribe(fh, s, 4, NULL);
1640 + }
1641 +}
1642 +
1643 +static const struct v4l2_ioctl_ops bcm2835_isp_node_ioctl_ops = {
1644 + .vidioc_querycap = bcm2835_isp_node_querycap,
1645 + .vidioc_g_fmt_vid_cap = bcm2835_isp_node_g_fmt,
1646 + .vidioc_g_fmt_vid_out = bcm2835_isp_node_g_fmt,
1647 + .vidioc_g_fmt_meta_cap = bcm2835_isp_node_g_fmt,
1648 + .vidioc_s_fmt_vid_cap = bcm2835_isp_node_s_fmt,
1649 + .vidioc_s_fmt_vid_out = bcm2835_isp_node_s_fmt,
1650 + .vidioc_s_fmt_meta_cap = bcm2835_isp_node_s_fmt,
1651 + .vidioc_try_fmt_vid_cap = bcm2835_isp_node_try_fmt,
1652 + .vidioc_try_fmt_vid_out = bcm2835_isp_node_try_fmt,
1653 + .vidioc_try_fmt_meta_cap = bcm2835_isp_node_try_fmt,
1654 + .vidioc_s_selection = bcm2835_isp_node_s_selection,
1655 + .vidioc_g_selection = bcm2835_isp_node_g_selection,
1656 +
1657 + .vidioc_enum_fmt_vid_cap = bcm2835_isp_node_enum_fmt,
1658 + .vidioc_enum_fmt_vid_out = bcm2835_isp_node_enum_fmt,
1659 + .vidioc_enum_fmt_meta_cap = bcm2835_isp_node_enum_fmt,
1660 + .vidioc_enum_framesizes = bcm2835_isp_enum_framesizes,
1661 +
1662 + .vidioc_reqbufs = vb2_ioctl_reqbufs,
1663 + .vidioc_querybuf = vb2_ioctl_querybuf,
1664 + .vidioc_qbuf = vb2_ioctl_qbuf,
1665 + .vidioc_dqbuf = vb2_ioctl_dqbuf,
1666 + .vidioc_expbuf = vb2_ioctl_expbuf,
1667 + .vidioc_create_bufs = vb2_ioctl_create_bufs,
1668 + .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
1669 +
1670 + .vidioc_streamon = vb2_ioctl_streamon,
1671 + .vidioc_streamoff = vb2_ioctl_streamoff,
1672 +
1673 + .vidioc_subscribe_event = bcm3285_isp_subscribe_event,
1674 + .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
1675 +};
1676 +
1677 +/*
1678 + * Size of the array to provide to the VPU when asking for the list of supported
1679 + * formats.
1680 + *
1681 + * The ISP component currently advertises 44 input formats, so add a small
1682 + * overhead on that. Should the component advertise more formats then the excess
1683 + * will be dropped and a warning logged.
1684 + */
1685 +#define MAX_SUPPORTED_ENCODINGS 50
1686 +
1687 +/* Populate node->supported_fmts with the formats supported by those ports. */
1688 +static int bcm2835_isp_get_supported_fmts(struct bcm2835_isp_node *node)
1689 +{
1690 + struct bcm2835_isp_dev *dev = node_get_dev(node);
1691 + struct bcm2835_isp_fmt const **list;
1692 + unsigned int i, j, num_encodings;
1693 + u32 fourccs[MAX_SUPPORTED_ENCODINGS];
1694 + u32 param_size = sizeof(fourccs);
1695 + int ret;
1696 +
1697 + ret = vchiq_mmal_port_parameter_get(dev->mmal_instance, node->port,
1698 + MMAL_PARAMETER_SUPPORTED_ENCODINGS,
1699 + &fourccs, &param_size);
1700 +
1701 + if (ret) {
1702 + if (ret == MMAL_MSG_STATUS_ENOSPC) {
1703 + v4l2_err(&dev->v4l2_dev,
1704 + "%s: port has more encoding than we provided space for. Some are dropped.\n",
1705 + __func__);
1706 + num_encodings = MAX_SUPPORTED_ENCODINGS;
1707 + } else {
1708 + v4l2_err(&dev->v4l2_dev, "%s: get_param ret %u.\n",
1709 + __func__, ret);
1710 + return -EINVAL;
1711 + }
1712 + } else {
1713 + num_encodings = param_size / sizeof(u32);
1714 + }
1715 +
1716 + /*
1717 + * Assume at this stage that all encodings will be supported in V4L2.
1718 + * Any that aren't supported will waste a very small amount of memory.
1719 + */
1720 + list = devm_kzalloc(dev->dev,
1721 + sizeof(struct bcm2835_isp_fmt *) * num_encodings,
1722 + GFP_KERNEL);
1723 + if (!list)
1724 + return -ENOMEM;
1725 + node->supported_fmts = list;
1726 +
1727 + for (i = 0, j = 0; i < num_encodings; i++) {
1728 + const struct bcm2835_isp_fmt *fmt = get_fmt(fourccs[i]);
1729 +
1730 + if (fmt) {
1731 + list[j] = fmt;
1732 + j++;
1733 + }
1734 + }
1735 + node->num_supported_fmts = j;
1736 +
1737 + return 0;
1738 +}
1739 +
1740 +/*
1741 + * Register a device node /dev/video<N> to go along with one of the ISP's input
1742 + * or output nodes.
1743 + */
1744 +static int register_node(struct bcm2835_isp_dev *dev,
1745 + struct bcm2835_isp_node *node,
1746 + int index)
1747 +{
1748 + struct video_device *vfd;
1749 + struct vb2_queue *queue;
1750 + int ret;
1751 +
1752 + mutex_init(&node->lock);
1753 +
1754 + node->dev = dev;
1755 + vfd = &node->vfd;
1756 + queue = &node->queue;
1757 + queue->type = index_to_queue_type(index);
1758 + /*
1759 + * Setup the node type-specific params.
1760 + *
1761 + * Only the OUTPUT node can set controls and crop windows. However,
1762 + * we must allow the s/g_selection ioctl on the stats node as v4l2
1763 + * compliance expects it to return a -ENOTTY, and the framework
1764 + * does not handle it if the ioctl is disabled.
1765 + */
1766 + switch (queue->type) {
1767 + case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1768 + vfd->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
1769 + node->id = index;
1770 + node->vfl_dir = VFL_DIR_TX;
1771 + node->name = "output";
1772 + node->port = &dev->component->input[node->id];
1773 + break;
1774 + case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1775 + vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
1776 + /* First Capture node starts at id 0, etc. */
1777 + node->id = index - BCM2835_ISP_NUM_OUTPUTS;
1778 + node->vfl_dir = VFL_DIR_RX;
1779 + node->name = "capture";
1780 + node->port = &dev->component->output[node->id];
1781 + v4l2_disable_ioctl(&node->vfd, VIDIOC_S_CTRL);
1782 + v4l2_disable_ioctl(&node->vfd, VIDIOC_S_SELECTION);
1783 + v4l2_disable_ioctl(&node->vfd, VIDIOC_G_SELECTION);
1784 + break;
1785 + case V4L2_BUF_TYPE_META_CAPTURE:
1786 + vfd->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING;
1787 + node->id = index - BCM2835_ISP_NUM_OUTPUTS;
1788 + node->vfl_dir = VFL_DIR_RX;
1789 + node->name = "stats";
1790 + node->port = &dev->component->output[node->id];
1791 + v4l2_disable_ioctl(&node->vfd, VIDIOC_S_CTRL);
1792 + v4l2_disable_ioctl(&node->vfd, VIDIOC_S_SELECTION);
1793 + v4l2_disable_ioctl(&node->vfd, VIDIOC_G_SELECTION);
1794 + break;
1795 + }
1796 +
1797 + /* We use the selection API instead of the old crop API. */
1798 + v4l2_disable_ioctl(vfd, VIDIOC_CROPCAP);
1799 + v4l2_disable_ioctl(vfd, VIDIOC_G_CROP);
1800 + v4l2_disable_ioctl(vfd, VIDIOC_S_CROP);
1801 +
1802 + ret = bcm2835_isp_get_supported_fmts(node);
1803 + if (ret)
1804 + return ret;
1805 +
1806 + /* Initialise the video node. */
1807 + vfd->vfl_type = VFL_TYPE_VIDEO;
1808 + vfd->fops = &bcm2835_isp_fops,
1809 + vfd->ioctl_ops = &bcm2835_isp_node_ioctl_ops,
1810 + vfd->minor = -1,
1811 + vfd->release = video_device_release_empty,
1812 + vfd->queue = &node->queue;
1813 + vfd->lock = &node->lock;
1814 + vfd->v4l2_dev = &dev->v4l2_dev;
1815 + vfd->vfl_dir = node->vfl_dir;
1816 +
1817 + node->q_data.fmt = get_default_format(node);
1818 + node->q_data.width = DEFAULT_DIM;
1819 + node->q_data.height = DEFAULT_DIM;
1820 + node->q_data.bytesperline =
1821 + get_bytesperline(DEFAULT_DIM, node->q_data.fmt);
1822 + node->q_data.sizeimage = node_is_stats(node) ?
1823 + node->port->recommended_buffer.size :
1824 + get_sizeimage(node->q_data.bytesperline,
1825 + node->q_data.width,
1826 + node->q_data.height,
1827 + node->q_data.fmt);
1828 +
1829 + queue->io_modes = VB2_MMAP | VB2_DMABUF;
1830 + queue->drv_priv = node;
1831 + queue->ops = &bcm2835_isp_node_queue_ops;
1832 + queue->mem_ops = &vb2_dma_contig_memops;
1833 + queue->buf_struct_size = sizeof(struct bcm2835_isp_buffer);
1834 + queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1835 + queue->dev = dev->dev;
1836 + queue->lock = &node->queue_lock;
1837 +
1838 + ret = vb2_queue_init(queue);
1839 + if (ret < 0) {
1840 + v4l2_info(&dev->v4l2_dev, "vb2_queue_init failed\n");
1841 + return ret;
1842 + }
1843 +
1844 + /* Set some controls and defaults, but only on the VIDEO_OUTPUT node. */
1845 + if (node_is_output(node)) {
1846 + unsigned int i;
1847 +
1848 + /* Use this ctrl template to assign custom ISP ctrls. */
1849 + struct v4l2_ctrl_config ctrl_template = {
1850 + .ops = &bcm2835_isp_ctrl_ops,
1851 + .type = V4L2_CTRL_TYPE_U8,
1852 + .def = 0,
1853 + .min = 0x00,
1854 + .max = 0xff,
1855 + .step = 1,
1856 + };
1857 +
1858 + /* 3 standard controls, and an array of custom controls */
1859 + ret = v4l2_ctrl_handler_init(&dev->ctrl_handler,
1860 + 3 + ARRAY_SIZE(custom_ctrls));
1861 + if (ret) {
1862 + v4l2_err(&dev->v4l2_dev, "ctrl_handler init failed (%d)\n",
1863 + ret);
1864 + goto queue_cleanup;
1865 + }
1866 +
1867 + dev->r_gain = 1000;
1868 + dev->b_gain = 1000;
1869 +
1870 + v4l2_ctrl_new_std(&dev->ctrl_handler, &bcm2835_isp_ctrl_ops,
1871 + V4L2_CID_RED_BALANCE, 1, 0xffff, 1,
1872 + dev->r_gain);
1873 +
1874 + v4l2_ctrl_new_std(&dev->ctrl_handler, &bcm2835_isp_ctrl_ops,
1875 + V4L2_CID_BLUE_BALANCE, 1, 0xffff, 1,
1876 + dev->b_gain);
1877 +
1878 + v4l2_ctrl_new_std(&dev->ctrl_handler, &bcm2835_isp_ctrl_ops,
1879 + V4L2_CID_DIGITAL_GAIN, 1, 0xffff, 1, 1000);
1880 +
1881 + for (i = 0; i < ARRAY_SIZE(custom_ctrls); i++) {
1882 + ctrl_template.name = custom_ctrls[i].name;
1883 + ctrl_template.id = custom_ctrls[i].id;
1884 + ctrl_template.dims[0] = custom_ctrls[i].size;
1885 + ctrl_template.flags = custom_ctrls[i].flags;
1886 + v4l2_ctrl_new_custom(&dev->ctrl_handler,
1887 + &ctrl_template, NULL);
1888 + }
1889 +
1890 + node->vfd.ctrl_handler = &dev->ctrl_handler;
1891 + if (dev->ctrl_handler.error) {
1892 + ret = dev->ctrl_handler.error;
1893 + v4l2_err(&dev->v4l2_dev, "controls init failed (%d)\n",
1894 + ret);
1895 + v4l2_ctrl_handler_free(&dev->ctrl_handler);
1896 + goto ctrl_cleanup;
1897 + }
1898 + }
1899 +
1900 + /* Define the device names */
1901 + snprintf(vfd->name, sizeof(node->vfd.name), "%s-%s%d", BCM2835_ISP_NAME,
1902 + node->name, node->id);
1903 +
1904 + ret = video_register_device(vfd, VFL_TYPE_VIDEO, video_nr + index);
1905 + if (ret) {
1906 + v4l2_err(&dev->v4l2_dev,
1907 + "Failed to register video %s[%d] device node\n",
1908 + node->name, node->id);
1909 + goto ctrl_cleanup;
1910 + }
1911 +
1912 + node->registered = true;
1913 + video_set_drvdata(vfd, node);
1914 +
1915 + v4l2_info(&dev->v4l2_dev,
1916 + "Device node %s[%d] registered as /dev/video%d\n",
1917 + node->name, node->id, vfd->num);
1918 +
1919 + return 0;
1920 +
1921 +ctrl_cleanup:
1922 + if (node_is_output(node))
1923 + v4l2_ctrl_handler_free(&dev->ctrl_handler);
1924 +queue_cleanup:
1925 + vb2_queue_release(&node->queue);
1926 + return ret;
1927 +}
1928 +
1929 +/* Unregister one of the /dev/video<N> nodes associated with the ISP. */
1930 +static void unregister_node(struct bcm2835_isp_node *node)
1931 +{
1932 + struct bcm2835_isp_dev *dev = node_get_dev(node);
1933 +
1934 + v4l2_info(&dev->v4l2_dev,
1935 + "Unregistering node %s[%d] device node /dev/video%d\n",
1936 + node->name, node->id, node->vfd.num);
1937 +
1938 + if (node->registered) {
1939 + video_unregister_device(&node->vfd);
1940 + if (node_is_output(node))
1941 + v4l2_ctrl_handler_free(&dev->ctrl_handler);
1942 + vb2_queue_release(&node->queue);
1943 + }
1944 +
1945 + /*
1946 + * node->supported_fmts.list is free'd automatically
1947 + * as a managed resource.
1948 + */
1949 + node->supported_fmts = NULL;
1950 + node->num_supported_fmts = 0;
1951 + node->vfd.ctrl_handler = NULL;
1952 + node->registered = false;
1953 +}
1954 +
1955 +static void media_controller_unregister(struct bcm2835_isp_dev *dev)
1956 +{
1957 + unsigned int i;
1958 +
1959 + v4l2_info(&dev->v4l2_dev, "Unregister from media controller\n");
1960 +
1961 + if (dev->media_device_registered) {
1962 + media_device_unregister(&dev->mdev);
1963 + media_device_cleanup(&dev->mdev);
1964 + dev->media_device_registered = false;
1965 + }
1966 +
1967 + kfree(dev->entity.name);
1968 + dev->entity.name = NULL;
1969 +
1970 + if (dev->media_entity_registered) {
1971 + media_device_unregister_entity(&dev->entity);
1972 + dev->media_entity_registered = false;
1973 + }
1974 +
1975 + for (i = 0; i < BCM2835_ISP_NUM_NODES; i++) {
1976 + struct bcm2835_isp_node *node = &dev->node[i];
1977 +
1978 + if (node->media_node_registered) {
1979 + media_remove_intf_links(node->intf_link->intf);
1980 + media_entity_remove_links(&dev->node[i].vfd.entity);
1981 + media_devnode_remove(node->intf_devnode);
1982 + media_device_unregister_entity(&node->vfd.entity);
1983 + kfree(node->vfd.entity.name);
1984 + }
1985 + node->media_node_registered = false;
1986 + }
1987 +
1988 + dev->v4l2_dev.mdev = NULL;
1989 +}
1990 +
1991 +static int media_controller_register_node(struct bcm2835_isp_dev *dev, int num)
1992 +{
1993 + struct bcm2835_isp_node *node = &dev->node[num];
1994 + struct media_entity *entity = &node->vfd.entity;
1995 + int output = node_is_output(node);
1996 + char *name;
1997 + int ret;
1998 +
1999 + v4l2_info(&dev->v4l2_dev,
2000 + "Register %s node %d with media controller\n",
2001 + output ? "output" : "capture", num);
2002 + entity->obj_type = MEDIA_ENTITY_TYPE_VIDEO_DEVICE;
2003 + entity->function = MEDIA_ENT_F_IO_V4L;
2004 + entity->info.dev.major = VIDEO_MAJOR;
2005 + entity->info.dev.minor = node->vfd.minor;
2006 + name = kmalloc(BCM2835_ISP_ENTITY_NAME_LEN, GFP_KERNEL);
2007 + if (!name) {
2008 + ret = -ENOMEM;
2009 + goto error_no_mem;
2010 + }
2011 + snprintf(name, BCM2835_ISP_ENTITY_NAME_LEN, "%s0-%s%d",
2012 + BCM2835_ISP_NAME, output ? "output" : "capture", num);
2013 + entity->name = name;
2014 + node->pad.flags = output ? MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK;
2015 + ret = media_entity_pads_init(entity, 1, &node->pad);
2016 + if (ret)
2017 + goto error_pads_init;
2018 + ret = media_device_register_entity(&dev->mdev, entity);
2019 + if (ret)
2020 + goto error_register_entity;
2021 +
2022 + node->intf_devnode = media_devnode_create(&dev->mdev,
2023 + MEDIA_INTF_T_V4L_VIDEO, 0,
2024 + VIDEO_MAJOR, node->vfd.minor);
2025 + if (!node->intf_devnode) {
2026 + ret = -ENOMEM;
2027 + goto error_devnode_create;
2028 + }
2029 +
2030 + node->intf_link = media_create_intf_link(entity,
2031 + &node->intf_devnode->intf,
2032 + MEDIA_LNK_FL_IMMUTABLE |
2033 + MEDIA_LNK_FL_ENABLED);
2034 + if (!node->intf_link) {
2035 + ret = -ENOMEM;
2036 + goto error_create_intf_link;
2037 + }
2038 +
2039 + if (output)
2040 + ret = media_create_pad_link(entity, 0, &dev->entity, num,
2041 + MEDIA_LNK_FL_IMMUTABLE |
2042 + MEDIA_LNK_FL_ENABLED);
2043 + else
2044 + ret = media_create_pad_link(&dev->entity, num, entity, 0,
2045 + MEDIA_LNK_FL_IMMUTABLE |
2046 + MEDIA_LNK_FL_ENABLED);
2047 + if (ret)
2048 + goto error_create_pad_link;
2049 +
2050 + dev->node[num].media_node_registered = true;
2051 + return 0;
2052 +
2053 +error_create_pad_link:
2054 + media_remove_intf_links(&node->intf_devnode->intf);
2055 +error_create_intf_link:
2056 + media_devnode_remove(node->intf_devnode);
2057 +error_devnode_create:
2058 + media_device_unregister_entity(&node->vfd.entity);
2059 +error_register_entity:
2060 +error_pads_init:
2061 + kfree(entity->name);
2062 + entity->name = NULL;
2063 +error_no_mem:
2064 + if (ret)
2065 + v4l2_info(&dev->v4l2_dev, "Error registering node\n");
2066 +
2067 + return ret;
2068 +}
2069 +
2070 +static int media_controller_register(struct bcm2835_isp_dev *dev)
2071 +{
2072 + char *name;
2073 + unsigned int i;
2074 + int ret;
2075 +
2076 + v4l2_dbg(2, debug, &dev->v4l2_dev, "Registering with media controller\n");
2077 + dev->mdev.dev = dev->dev;
2078 + strscpy(dev->mdev.model, "bcm2835-isp",
2079 + sizeof(dev->mdev.model));
2080 + strscpy(dev->mdev.bus_info, "platform:bcm2835-isp",
2081 + sizeof(dev->mdev.bus_info));
2082 + media_device_init(&dev->mdev);
2083 + dev->v4l2_dev.mdev = &dev->mdev;
2084 +
2085 + v4l2_dbg(2, debug, &dev->v4l2_dev, "Register entity for nodes\n");
2086 +
2087 + name = kmalloc(BCM2835_ISP_ENTITY_NAME_LEN, GFP_KERNEL);
2088 + if (!name) {
2089 + ret = -ENOMEM;
2090 + goto done;
2091 + }
2092 + snprintf(name, BCM2835_ISP_ENTITY_NAME_LEN, "bcm2835_isp0");
2093 + dev->entity.name = name;
2094 + dev->entity.obj_type = MEDIA_ENTITY_TYPE_BASE;
2095 + dev->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
2096 +
2097 + for (i = 0; i < BCM2835_ISP_NUM_NODES; i++) {
2098 + dev->pad[i].flags = node_is_output(&dev->node[i]) ?
2099 + MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
2100 + }
2101 +
2102 + ret = media_entity_pads_init(&dev->entity, BCM2835_ISP_NUM_NODES,
2103 + dev->pad);
2104 + if (ret)
2105 + goto done;
2106 +
2107 + ret = media_device_register_entity(&dev->mdev, &dev->entity);
2108 + if (ret)
2109 + goto done;
2110 +
2111 + dev->media_entity_registered = true;
2112 + for (i = 0; i < BCM2835_ISP_NUM_NODES; i++) {
2113 + ret = media_controller_register_node(dev, i);
2114 + if (ret)
2115 + goto done;
2116 + }
2117 +
2118 + ret = media_device_register(&dev->mdev);
2119 + if (!ret)
2120 + dev->media_device_registered = true;
2121 +done:
2122 + return ret;
2123 +}
2124 +
2125 +static int bcm2835_isp_remove(struct platform_device *pdev)
2126 +{
2127 + struct bcm2835_isp_dev *dev = platform_get_drvdata(pdev);
2128 + unsigned int i;
2129 +
2130 + media_controller_unregister(dev);
2131 +
2132 + for (i = 0; i < BCM2835_ISP_NUM_NODES; i++)
2133 + unregister_node(&dev->node[i]);
2134 +
2135 + v4l2_device_unregister(&dev->v4l2_dev);
2136 +
2137 + if (dev->component)
2138 + vchiq_mmal_component_finalise(dev->mmal_instance,
2139 + dev->component);
2140 +
2141 + vchiq_mmal_finalise(dev->mmal_instance);
2142 +
2143 + return 0;
2144 +}
2145 +
2146 +static int bcm2835_isp_probe(struct platform_device *pdev)
2147 +{
2148 + struct bcm2835_isp_dev *dev;
2149 + unsigned int i;
2150 + int ret;
2151 +
2152 + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
2153 + if (!dev)
2154 + return -ENOMEM;
2155 +
2156 + dev->dev = &pdev->dev;
2157 +
2158 + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
2159 + if (ret)
2160 + return ret;
2161 +
2162 + ret = vchiq_mmal_init(&dev->mmal_instance);
2163 + if (ret) {
2164 + v4l2_device_unregister(&dev->v4l2_dev);
2165 + return ret;
2166 + }
2167 +
2168 + ret = vchiq_mmal_component_init(dev->mmal_instance, "ril.isp",
2169 + &dev->component);
2170 + if (ret) {
2171 + v4l2_err(&dev->v4l2_dev,
2172 + "%s: failed to create ril.isp component\n", __func__);
2173 + goto error;
2174 + }
2175 +
2176 + if (dev->component->inputs < BCM2835_ISP_NUM_OUTPUTS ||
2177 + dev->component->outputs < BCM2835_ISP_NUM_CAPTURES +
2178 + BCM2835_ISP_NUM_METADATA) {
2179 + v4l2_err(&dev->v4l2_dev,
2180 + "%s: ril.isp returned %d i/p (%d expected), %d o/p (%d expected) ports\n",
2181 + __func__, dev->component->inputs,
2182 + BCM2835_ISP_NUM_OUTPUTS,
2183 + dev->component->outputs,
2184 + BCM2835_ISP_NUM_CAPTURES + BCM2835_ISP_NUM_METADATA);
2185 + goto error;
2186 + }
2187 +
2188 + atomic_set(&dev->num_streaming, 0);
2189 +
2190 + for (i = 0; i < BCM2835_ISP_NUM_NODES; i++) {
2191 + struct bcm2835_isp_node *node = &dev->node[i];
2192 +
2193 + ret = register_node(dev, node, i);
2194 + if (ret)
2195 + goto error;
2196 + }
2197 +
2198 + ret = media_controller_register(dev);
2199 + if (ret)
2200 + goto error;
2201 +
2202 + platform_set_drvdata(pdev, dev);
2203 + v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n", BCM2835_ISP_NAME);
2204 + return 0;
2205 +
2206 +error:
2207 + bcm2835_isp_remove(pdev);
2208 +
2209 + return ret;
2210 +}
2211 +
2212 +static struct platform_driver bcm2835_isp_pdrv = {
2213 + .probe = bcm2835_isp_probe,
2214 + .remove = bcm2835_isp_remove,
2215 + .driver = {
2216 + .name = BCM2835_ISP_NAME,
2217 + },
2218 +};
2219 +
2220 +module_platform_driver(bcm2835_isp_pdrv);
2221 +
2222 +MODULE_DESCRIPTION("BCM2835 ISP driver");
2223 +MODULE_AUTHOR("Naushir Patuck <naush@raspberrypi.com>");
2224 +MODULE_LICENSE("GPL");
2225 +MODULE_VERSION("1.0");
2226 +MODULE_ALIAS("platform:bcm2835-isp");
2227 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-encodings.h
2228 +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-encodings.h
2229 @@ -113,6 +113,10 @@
2230 */
2231 #define MMAL_ENCODING_EGL_IMAGE MMAL_FOURCC('E', 'G', 'L', 'I')
2232
2233 +/** ISP image statistics format
2234 + */
2235 +#define MMAL_ENCODING_BRCM_STATS MMAL_FOURCC('S', 'T', 'A', 'T')
2236 +
2237 /* }@ */
2238
2239 /** \name Pre-defined audio encodings */
2240 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h
2241 +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h
2242 @@ -223,6 +223,62 @@ enum mmal_parameter_camera_type {
2243 MMAL_PARAMETER_SHUTTER_SPEED,
2244 /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */
2245 MMAL_PARAMETER_CUSTOM_AWB_GAINS,
2246 + /**< Takes a @ref MMAL_PARAMETER_CAMERA_SETTINGS_T */
2247 + MMAL_PARAMETER_CAMERA_SETTINGS,
2248 + /**< Takes a @ref MMAL_PARAMETER_PRIVACY_INDICATOR_T */
2249 + MMAL_PARAMETER_PRIVACY_INDICATOR,
2250 + /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
2251 + MMAL_PARAMETER_VIDEO_DENOISE,
2252 + /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
2253 + MMAL_PARAMETER_STILLS_DENOISE,
2254 + /**< Takes a @ref MMAL_PARAMETER_CAMERA_ANNOTATE_T */
2255 + MMAL_PARAMETER_ANNOTATE,
2256 + /**< Takes a @ref MMAL_PARAMETER_STEREOSCOPIC_MODE_T */
2257 + MMAL_PARAMETER_STEREOSCOPIC_MODE,
2258 + /**< Takes a @ref MMAL_PARAMETER_CAMERA_INTERFACE_T */
2259 + MMAL_PARAMETER_CAMERA_INTERFACE,
2260 + /**< Takes a @ref MMAL_PARAMETER_CAMERA_CLOCKING_MODE_T */
2261 + MMAL_PARAMETER_CAMERA_CLOCKING_MODE,
2262 + /**< Takes a @ref MMAL_PARAMETER_CAMERA_RX_CONFIG_T */
2263 + MMAL_PARAMETER_CAMERA_RX_CONFIG,
2264 + /**< Takes a @ref MMAL_PARAMETER_CAMERA_RX_TIMING_T */
2265 + MMAL_PARAMETER_CAMERA_RX_TIMING,
2266 + /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
2267 + MMAL_PARAMETER_DPF_CONFIG,
2268 +
2269 + /* 0x50 */
2270 + /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
2271 + MMAL_PARAMETER_JPEG_RESTART_INTERVAL,
2272 + /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
2273 + MMAL_PARAMETER_CAMERA_ISP_BLOCK_OVERRIDE,
2274 + /**< Takes a @ref MMAL_PARAMETER_LENS_SHADING_T */
2275 + MMAL_PARAMETER_LENS_SHADING_OVERRIDE,
2276 + /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
2277 + MMAL_PARAMETER_BLACK_LEVEL,
2278 + /**< Takes a @ref MMAL_PARAMETER_RESIZE_T */
2279 + MMAL_PARAMETER_RESIZE_PARAMS,
2280 + /**< Takes a @ref MMAL_PARAMETER_CROP_T */
2281 + MMAL_PARAMETER_CROP,
2282 + /**< Takes a @ref MMAL_PARAMETER_INT32_T */
2283 + MMAL_PARAMETER_OUTPUT_SHIFT,
2284 + /**< Takes a @ref MMAL_PARAMETER_INT32_T */
2285 + MMAL_PARAMETER_CCM_SHIFT,
2286 + /**< Takes a @ref MMAL_PARAMETER_CUSTOM_CCM_T */
2287 + MMAL_PARAMETER_CUSTOM_CCM,
2288 + /**< Takes a @ref MMAL_PARAMETER_RATIONAL_T */
2289 + MMAL_PARAMETER_ANALOG_GAIN,
2290 + /**< Takes a @ref MMAL_PARAMETER_RATIONAL_T */
2291 + MMAL_PARAMETER_DIGITAL_GAIN,
2292 + /**< Takes a @ref MMAL_PARAMETER_DENOISE_T */
2293 + MMAL_PARAMETER_DENOISE,
2294 + /**< Takes a @ref MMAL_PARAMETER_SHARPEN_T */
2295 + MMAL_PARAMETER_SHARPEN,
2296 + /**< Takes a @ref MMAL_PARAMETER_GEQ_T */
2297 + MMAL_PARAMETER_GEQ,
2298 + /**< Tales a @ref MMAP_PARAMETER_DPC_T */
2299 + MMAL_PARAMETER_DPC,
2300 + /**< Tales a @ref MMAP_PARAMETER_GAMMA_T */
2301 + MMAL_PARAMETER_GAMMA,
2302 /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
2303 MMAL_PARAMETER_JPEG_IJG_SCALING,
2304 };
2305 @@ -791,7 +847,102 @@ struct mmal_parameter_camera_info {
2306 struct mmal_parameter_camera_info_camera
2307 cameras[MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS];
2308 struct mmal_parameter_camera_info_flash
2309 - flashes[MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES];
2310 + flashes[MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES];
2311 +};
2312 +
2313 +struct mmal_parameter_ccm {
2314 + struct s32_fract ccm[3][3];
2315 + s32 offsets[3];
2316 +};
2317 +
2318 +struct mmal_parameter_custom_ccm {
2319 + u32 enabled; /**< Enable the custom CCM. */
2320 + struct mmal_parameter_ccm ccm; /**< CCM to be used. */
2321 +};
2322 +
2323 +struct mmal_parameter_lens_shading {
2324 + u32 enabled;
2325 + u32 grid_cell_size;
2326 + u32 grid_width;
2327 + u32 grid_stride;
2328 + u32 grid_height;
2329 + u32 mem_handle_table;
2330 + u32 ref_transform;
2331 +};
2332 +
2333 +enum mmal_parameter_ls_gain_format_type {
2334 + MMAL_PARAMETER_LS_GAIN_FORMAT_TYPE_U0P8_1 = 0,
2335 + MMAL_PARAMETER_LS_GAIN_FORMAT_TYPE_U1P7_0 = 1,
2336 + MMAL_PARAMETER_LS_GAIN_FORMAT_TYPE_U1P7_1 = 2,
2337 + MMAL_PARAMETER_LS_GAIN_FORMAT_TYPE_U2P6_0 = 3,
2338 + MMAL_PARAMETER_LS_GAIN_FORMAT_TYPE_U2P6_1 = 4,
2339 + MMAL_PARAMETER_LS_GAIN_FORMAT_TYPE_U3P5_0 = 5,
2340 + MMAL_PARAMETER_LS_GAIN_FORMAT_TYPE_U3P5_1 = 6,
2341 + MMAL_PARAMETER_LS_GAIN_FORMAT_TYPE_U4P10 = 7,
2342 + MMAL_PARAMETER_LS_GAIN_FORMAT_TYPE_DUMMY = 0x7FFFFFFF
2343 +};
2344 +
2345 +struct mmal_parameter_lens_shading_v2 {
2346 + u32 enabled;
2347 + u32 grid_cell_size;
2348 + u32 grid_width;
2349 + u32 grid_stride;
2350 + u32 grid_height;
2351 + u32 mem_handle_table;
2352 + u32 ref_transform;
2353 + u32 corner_sampled;
2354 + enum mmal_parameter_ls_gain_format_type gain_format;
2355 +};
2356 +
2357 +struct mmal_parameter_black_level {
2358 + u32 enabled;
2359 + u16 black_level_r;
2360 + u16 black_level_g;
2361 + u16 black_level_b;
2362 + u8 pad_[2]; /* Unused */
2363 +};
2364 +
2365 +struct mmal_parameter_geq {
2366 + u32 enabled;
2367 + u32 offset;
2368 + struct s32_fract slope;
2369 +};
2370 +
2371 +#define MMAL_NUM_GAMMA_PTS 33
2372 +struct mmal_parameter_gamma {
2373 + u32 enabled;
2374 + u16 x[MMAL_NUM_GAMMA_PTS];
2375 + u16 y[MMAL_NUM_GAMMA_PTS];
2376 +};
2377 +
2378 +struct mmal_parameter_denoise {
2379 + u32 enabled;
2380 + u32 constant;
2381 + struct s32_fract slope;
2382 + struct s32_fract strength;
2383 +};
2384 +
2385 +struct mmal_parameter_sharpen {
2386 + u32 enabled;
2387 + struct s32_fract threshold;
2388 + struct s32_fract strength;
2389 + struct s32_fract limit;
2390 +};
2391 +
2392 +enum mmal_dpc_mode {
2393 + MMAL_DPC_MODE_OFF = 0,
2394 + MMAL_DPC_MODE_NORMAL = 1,
2395 + MMAL_DPC_MODE_STRONG = 2,
2396 + MMAL_DPC_MODE_MAX = 0x7FFFFFFF,
2397 +};
2398 +
2399 +struct mmal_parameter_dpc {
2400 + u32 enabled;
2401 + u32 strength;
2402 +};
2403 +
2404 +struct mmal_parameter_crop {
2405 + struct vchiq_mmal_rect rect;
2406 };
2407
2408 #endif