1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * vimc-debayer.c Virtual Media Controller Driver
5 * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
8 #include <linux/moduleparam.h>
9 #include <linux/platform_device.h>
10 #include <linux/vmalloc.h>
11 #include <linux/v4l2-mediabus.h>
12 #include <media/v4l2-ctrls.h>
13 #include <media/v4l2-event.h>
14 #include <media/v4l2-subdev.h>
16 #include "vimc-common.h"
18 enum vimc_deb_rgb_colors
{
24 struct vimc_deb_pix_map
{
26 enum vimc_deb_rgb_colors order
[2][2];
29 struct vimc_deb_device
{
30 struct vimc_ent_device ved
;
31 struct v4l2_subdev sd
;
32 /* The active format */
33 struct v4l2_mbus_framefmt sink_fmt
;
35 void (*set_rgb_src
)(struct vimc_deb_device
*vdeb
, unsigned int lin
,
36 unsigned int col
, unsigned int rgb
[3]);
37 /* Values calculated when the stream starts */
39 const struct vimc_deb_pix_map
*sink_pix_map
;
40 unsigned int sink_bpp
;
41 unsigned int mean_win_size
;
42 struct v4l2_ctrl_handler hdl
;
43 struct media_pad pads
[2];
46 static const struct v4l2_mbus_framefmt sink_fmt_default
= {
49 .code
= MEDIA_BUS_FMT_SRGGB8_1X8
,
50 .field
= V4L2_FIELD_NONE
,
51 .colorspace
= V4L2_COLORSPACE_DEFAULT
,
54 static const struct vimc_deb_pix_map vimc_deb_pix_map_list
[] = {
56 .code
= MEDIA_BUS_FMT_SBGGR8_1X8
,
57 .order
= { { VIMC_DEB_BLUE
, VIMC_DEB_GREEN
},
58 { VIMC_DEB_GREEN
, VIMC_DEB_RED
} }
61 .code
= MEDIA_BUS_FMT_SGBRG8_1X8
,
62 .order
= { { VIMC_DEB_GREEN
, VIMC_DEB_BLUE
},
63 { VIMC_DEB_RED
, VIMC_DEB_GREEN
} }
66 .code
= MEDIA_BUS_FMT_SGRBG8_1X8
,
67 .order
= { { VIMC_DEB_GREEN
, VIMC_DEB_RED
},
68 { VIMC_DEB_BLUE
, VIMC_DEB_GREEN
} }
71 .code
= MEDIA_BUS_FMT_SRGGB8_1X8
,
72 .order
= { { VIMC_DEB_RED
, VIMC_DEB_GREEN
},
73 { VIMC_DEB_GREEN
, VIMC_DEB_BLUE
} }
76 .code
= MEDIA_BUS_FMT_SBGGR10_1X10
,
77 .order
= { { VIMC_DEB_BLUE
, VIMC_DEB_GREEN
},
78 { VIMC_DEB_GREEN
, VIMC_DEB_RED
} }
81 .code
= MEDIA_BUS_FMT_SGBRG10_1X10
,
82 .order
= { { VIMC_DEB_GREEN
, VIMC_DEB_BLUE
},
83 { VIMC_DEB_RED
, VIMC_DEB_GREEN
} }
86 .code
= MEDIA_BUS_FMT_SGRBG10_1X10
,
87 .order
= { { VIMC_DEB_GREEN
, VIMC_DEB_RED
},
88 { VIMC_DEB_BLUE
, VIMC_DEB_GREEN
} }
91 .code
= MEDIA_BUS_FMT_SRGGB10_1X10
,
92 .order
= { { VIMC_DEB_RED
, VIMC_DEB_GREEN
},
93 { VIMC_DEB_GREEN
, VIMC_DEB_BLUE
} }
96 .code
= MEDIA_BUS_FMT_SBGGR12_1X12
,
97 .order
= { { VIMC_DEB_BLUE
, VIMC_DEB_GREEN
},
98 { VIMC_DEB_GREEN
, VIMC_DEB_RED
} }
101 .code
= MEDIA_BUS_FMT_SGBRG12_1X12
,
102 .order
= { { VIMC_DEB_GREEN
, VIMC_DEB_BLUE
},
103 { VIMC_DEB_RED
, VIMC_DEB_GREEN
} }
106 .code
= MEDIA_BUS_FMT_SGRBG12_1X12
,
107 .order
= { { VIMC_DEB_GREEN
, VIMC_DEB_RED
},
108 { VIMC_DEB_BLUE
, VIMC_DEB_GREEN
} }
111 .code
= MEDIA_BUS_FMT_SRGGB12_1X12
,
112 .order
= { { VIMC_DEB_RED
, VIMC_DEB_GREEN
},
113 { VIMC_DEB_GREEN
, VIMC_DEB_BLUE
} }
117 static const struct vimc_deb_pix_map
*vimc_deb_pix_map_by_code(u32 code
)
121 for (i
= 0; i
< ARRAY_SIZE(vimc_deb_pix_map_list
); i
++)
122 if (vimc_deb_pix_map_list
[i
].code
== code
)
123 return &vimc_deb_pix_map_list
[i
];
128 static int vimc_deb_init_cfg(struct v4l2_subdev
*sd
,
129 struct v4l2_subdev_pad_config
*cfg
)
131 struct vimc_deb_device
*vdeb
= v4l2_get_subdevdata(sd
);
132 struct v4l2_mbus_framefmt
*mf
;
135 mf
= v4l2_subdev_get_try_format(sd
, cfg
, 0);
136 *mf
= sink_fmt_default
;
138 for (i
= 1; i
< sd
->entity
.num_pads
; i
++) {
139 mf
= v4l2_subdev_get_try_format(sd
, cfg
, i
);
140 *mf
= sink_fmt_default
;
141 mf
->code
= vdeb
->src_code
;
147 static int vimc_deb_enum_mbus_code(struct v4l2_subdev
*sd
,
148 struct v4l2_subdev_pad_config
*cfg
,
149 struct v4l2_subdev_mbus_code_enum
*code
)
151 /* We only support one format for source pads */
152 if (VIMC_IS_SRC(code
->pad
)) {
153 struct vimc_deb_device
*vdeb
= v4l2_get_subdevdata(sd
);
158 code
->code
= vdeb
->src_code
;
160 if (code
->index
>= ARRAY_SIZE(vimc_deb_pix_map_list
))
163 code
->code
= vimc_deb_pix_map_list
[code
->index
].code
;
169 static int vimc_deb_enum_frame_size(struct v4l2_subdev
*sd
,
170 struct v4l2_subdev_pad_config
*cfg
,
171 struct v4l2_subdev_frame_size_enum
*fse
)
173 struct vimc_deb_device
*vdeb
= v4l2_get_subdevdata(sd
);
178 if (VIMC_IS_SINK(fse
->pad
)) {
179 const struct vimc_deb_pix_map
*vpix
=
180 vimc_deb_pix_map_by_code(fse
->code
);
184 } else if (fse
->code
!= vdeb
->src_code
) {
188 fse
->min_width
= VIMC_FRAME_MIN_WIDTH
;
189 fse
->max_width
= VIMC_FRAME_MAX_WIDTH
;
190 fse
->min_height
= VIMC_FRAME_MIN_HEIGHT
;
191 fse
->max_height
= VIMC_FRAME_MAX_HEIGHT
;
196 static int vimc_deb_get_fmt(struct v4l2_subdev
*sd
,
197 struct v4l2_subdev_pad_config
*cfg
,
198 struct v4l2_subdev_format
*fmt
)
200 struct vimc_deb_device
*vdeb
= v4l2_get_subdevdata(sd
);
202 /* Get the current sink format */
203 fmt
->format
= fmt
->which
== V4L2_SUBDEV_FORMAT_TRY
?
204 *v4l2_subdev_get_try_format(sd
, cfg
, 0) :
207 /* Set the right code for the source pad */
208 if (VIMC_IS_SRC(fmt
->pad
))
209 fmt
->format
.code
= vdeb
->src_code
;
214 static void vimc_deb_adjust_sink_fmt(struct v4l2_mbus_framefmt
*fmt
)
216 const struct vimc_deb_pix_map
*vpix
;
218 /* Don't accept a code that is not on the debayer table */
219 vpix
= vimc_deb_pix_map_by_code(fmt
->code
);
221 fmt
->code
= sink_fmt_default
.code
;
223 fmt
->width
= clamp_t(u32
, fmt
->width
, VIMC_FRAME_MIN_WIDTH
,
224 VIMC_FRAME_MAX_WIDTH
) & ~1;
225 fmt
->height
= clamp_t(u32
, fmt
->height
, VIMC_FRAME_MIN_HEIGHT
,
226 VIMC_FRAME_MAX_HEIGHT
) & ~1;
228 if (fmt
->field
== V4L2_FIELD_ANY
)
229 fmt
->field
= sink_fmt_default
.field
;
231 vimc_colorimetry_clamp(fmt
);
234 static int vimc_deb_set_fmt(struct v4l2_subdev
*sd
,
235 struct v4l2_subdev_pad_config
*cfg
,
236 struct v4l2_subdev_format
*fmt
)
238 struct vimc_deb_device
*vdeb
= v4l2_get_subdevdata(sd
);
239 struct v4l2_mbus_framefmt
*sink_fmt
;
241 if (fmt
->which
== V4L2_SUBDEV_FORMAT_ACTIVE
) {
242 /* Do not change the format while stream is on */
246 sink_fmt
= &vdeb
->sink_fmt
;
248 sink_fmt
= v4l2_subdev_get_try_format(sd
, cfg
, 0);
252 * Do not change the format of the source pad,
253 * it is propagated from the sink
255 if (VIMC_IS_SRC(fmt
->pad
)) {
256 fmt
->format
= *sink_fmt
;
257 /* TODO: Add support for other formats */
258 fmt
->format
.code
= vdeb
->src_code
;
260 /* Set the new format in the sink pad */
261 vimc_deb_adjust_sink_fmt(&fmt
->format
);
263 dev_dbg(vdeb
->ved
.dev
, "%s: sink format update: "
264 "old:%dx%d (0x%x, %d, %d, %d, %d) "
265 "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vdeb
->sd
.name
,
267 sink_fmt
->width
, sink_fmt
->height
, sink_fmt
->code
,
268 sink_fmt
->colorspace
, sink_fmt
->quantization
,
269 sink_fmt
->xfer_func
, sink_fmt
->ycbcr_enc
,
271 fmt
->format
.width
, fmt
->format
.height
, fmt
->format
.code
,
272 fmt
->format
.colorspace
, fmt
->format
.quantization
,
273 fmt
->format
.xfer_func
, fmt
->format
.ycbcr_enc
);
275 *sink_fmt
= fmt
->format
;
281 static const struct v4l2_subdev_pad_ops vimc_deb_pad_ops
= {
282 .init_cfg
= vimc_deb_init_cfg
,
283 .enum_mbus_code
= vimc_deb_enum_mbus_code
,
284 .enum_frame_size
= vimc_deb_enum_frame_size
,
285 .get_fmt
= vimc_deb_get_fmt
,
286 .set_fmt
= vimc_deb_set_fmt
,
289 static void vimc_deb_set_rgb_mbus_fmt_rgb888_1x24(struct vimc_deb_device
*vdeb
,
294 unsigned int i
, index
;
296 index
= VIMC_FRAME_INDEX(lin
, col
, vdeb
->sink_fmt
.width
, 3);
297 for (i
= 0; i
< 3; i
++)
298 vdeb
->src_frame
[index
+ i
] = rgb
[i
];
301 static int vimc_deb_s_stream(struct v4l2_subdev
*sd
, int enable
)
303 struct vimc_deb_device
*vdeb
= v4l2_get_subdevdata(sd
);
306 const struct vimc_pix_map
*vpix
;
307 unsigned int frame_size
;
312 /* Calculate the frame size of the source pad */
313 vpix
= vimc_pix_map_by_code(vdeb
->src_code
);
314 frame_size
= vdeb
->sink_fmt
.width
* vdeb
->sink_fmt
.height
*
317 /* Save the bytes per pixel of the sink */
318 vpix
= vimc_pix_map_by_code(vdeb
->sink_fmt
.code
);
319 vdeb
->sink_bpp
= vpix
->bpp
;
321 /* Get the corresponding pixel map from the table */
323 vimc_deb_pix_map_by_code(vdeb
->sink_fmt
.code
);
326 * Allocate the frame buffer. Use vmalloc to be able to
327 * allocate a large amount of memory
329 vdeb
->src_frame
= vmalloc(frame_size
);
330 if (!vdeb
->src_frame
)
334 if (!vdeb
->src_frame
)
337 vfree(vdeb
->src_frame
);
338 vdeb
->src_frame
= NULL
;
344 static const struct v4l2_subdev_core_ops vimc_deb_core_ops
= {
345 .log_status
= v4l2_ctrl_subdev_log_status
,
346 .subscribe_event
= v4l2_ctrl_subdev_subscribe_event
,
347 .unsubscribe_event
= v4l2_event_subdev_unsubscribe
,
350 static const struct v4l2_subdev_video_ops vimc_deb_video_ops
= {
351 .s_stream
= vimc_deb_s_stream
,
354 static const struct v4l2_subdev_ops vimc_deb_ops
= {
355 .core
= &vimc_deb_core_ops
,
356 .pad
= &vimc_deb_pad_ops
,
357 .video
= &vimc_deb_video_ops
,
360 static unsigned int vimc_deb_get_val(const u8
*bytes
,
361 const unsigned int n_bytes
)
364 unsigned int acc
= 0;
366 for (i
= 0; i
< n_bytes
; i
++)
367 acc
= acc
+ (bytes
[i
] << (8 * i
));
372 static void vimc_deb_calc_rgb_sink(struct vimc_deb_device
*vdeb
,
374 const unsigned int lin
,
375 const unsigned int col
,
378 unsigned int i
, seek
, wlin
, wcol
;
379 unsigned int n_rgb
[3] = {0, 0, 0};
381 for (i
= 0; i
< 3; i
++)
385 * Calculate how many we need to subtract to get to the pixel in
386 * the top left corner of the mean window (considering the current
387 * pixel as the center)
389 seek
= vdeb
->mean_win_size
/ 2;
391 /* Sum the values of the colors in the mean window */
393 dev_dbg(vdeb
->ved
.dev
,
394 "deb: %s: --- Calc pixel %dx%d, window mean %d, seek %d ---\n",
395 vdeb
->sd
.name
, lin
, col
, vdeb
->sink_fmt
.height
, seek
);
398 * Iterate through all the lines in the mean window, start
399 * with zero if the pixel is outside the frame and don't pass
400 * the height when the pixel is in the bottom border of the
403 for (wlin
= seek
> lin
? 0 : lin
- seek
;
404 wlin
< lin
+ seek
+ 1 && wlin
< vdeb
->sink_fmt
.height
;
408 * Iterate through all the columns in the mean window, start
409 * with zero if the pixel is outside the frame and don't pass
410 * the width when the pixel is in the right border of the
413 for (wcol
= seek
> col
? 0 : col
- seek
;
414 wcol
< col
+ seek
+ 1 && wcol
< vdeb
->sink_fmt
.width
;
416 enum vimc_deb_rgb_colors color
;
419 /* Check which color this pixel is */
420 color
= vdeb
->sink_pix_map
->order
[wlin
% 2][wcol
% 2];
422 index
= VIMC_FRAME_INDEX(wlin
, wcol
,
423 vdeb
->sink_fmt
.width
,
426 dev_dbg(vdeb
->ved
.dev
,
427 "deb: %s: RGB CALC: frame index %d, win pos %dx%d, color %d\n",
428 vdeb
->sd
.name
, index
, wlin
, wcol
, color
);
431 rgb
[color
] = rgb
[color
] +
432 vimc_deb_get_val(&frame
[index
], vdeb
->sink_bpp
);
434 /* Save how many values we already added */
437 dev_dbg(vdeb
->ved
.dev
, "deb: %s: RGB CALC: val %d, n %d\n",
438 vdeb
->sd
.name
, rgb
[color
], n_rgb
[color
]);
442 /* Calculate the mean */
443 for (i
= 0; i
< 3; i
++) {
444 dev_dbg(vdeb
->ved
.dev
,
445 "deb: %s: PRE CALC: %dx%d Color %d, val %d, n %d\n",
446 vdeb
->sd
.name
, lin
, col
, i
, rgb
[i
], n_rgb
[i
]);
449 rgb
[i
] = rgb
[i
] / n_rgb
[i
];
451 dev_dbg(vdeb
->ved
.dev
,
452 "deb: %s: FINAL CALC: %dx%d Color %d, val %d\n",
453 vdeb
->sd
.name
, lin
, col
, i
, rgb
[i
]);
457 static void *vimc_deb_process_frame(struct vimc_ent_device
*ved
,
458 const void *sink_frame
)
460 struct vimc_deb_device
*vdeb
= container_of(ved
, struct vimc_deb_device
,
465 /* If the stream in this node is not active, just return */
466 if (!vdeb
->src_frame
)
467 return ERR_PTR(-EINVAL
);
469 for (i
= 0; i
< vdeb
->sink_fmt
.height
; i
++)
470 for (j
= 0; j
< vdeb
->sink_fmt
.width
; j
++) {
471 vimc_deb_calc_rgb_sink(vdeb
, sink_frame
, i
, j
, rgb
);
472 vdeb
->set_rgb_src(vdeb
, i
, j
, rgb
);
475 return vdeb
->src_frame
;
478 static int vimc_deb_s_ctrl(struct v4l2_ctrl
*ctrl
)
480 struct vimc_deb_device
*vdeb
=
481 container_of(ctrl
->handler
, struct vimc_deb_device
, hdl
);
484 case VIMC_CID_MEAN_WIN_SIZE
:
485 vdeb
->mean_win_size
= ctrl
->val
;
493 static const struct v4l2_ctrl_ops vimc_deb_ctrl_ops
= {
494 .s_ctrl
= vimc_deb_s_ctrl
,
497 static void vimc_deb_release(struct v4l2_subdev
*sd
)
499 struct vimc_deb_device
*vdeb
=
500 container_of(sd
, struct vimc_deb_device
, sd
);
502 v4l2_ctrl_handler_free(&vdeb
->hdl
);
503 media_entity_cleanup(vdeb
->ved
.ent
);
507 static const struct v4l2_subdev_internal_ops vimc_deb_int_ops
= {
508 .release
= vimc_deb_release
,
511 void vimc_deb_rm(struct vimc_device
*vimc
, struct vimc_ent_device
*ved
)
513 struct vimc_deb_device
*vdeb
;
515 vdeb
= container_of(ved
, struct vimc_deb_device
, ved
);
516 v4l2_device_unregister_subdev(&vdeb
->sd
);
519 static const struct v4l2_ctrl_config vimc_deb_ctrl_class
= {
520 .flags
= V4L2_CTRL_FLAG_READ_ONLY
| V4L2_CTRL_FLAG_WRITE_ONLY
,
521 .id
= VIMC_CID_VIMC_CLASS
,
522 .name
= "VIMC Controls",
523 .type
= V4L2_CTRL_TYPE_CTRL_CLASS
,
526 static const struct v4l2_ctrl_config vimc_deb_ctrl_mean_win_size
= {
527 .ops
= &vimc_deb_ctrl_ops
,
528 .id
= VIMC_CID_MEAN_WIN_SIZE
,
529 .name
= "Debayer Mean Window Size",
530 .type
= V4L2_CTRL_TYPE_INTEGER
,
537 struct vimc_ent_device
*vimc_deb_add(struct vimc_device
*vimc
,
538 const char *vcfg_name
)
540 struct v4l2_device
*v4l2_dev
= &vimc
->v4l2_dev
;
541 struct vimc_deb_device
*vdeb
;
544 /* Allocate the vdeb struct */
545 vdeb
= kzalloc(sizeof(*vdeb
), GFP_KERNEL
);
549 /* Create controls: */
550 v4l2_ctrl_handler_init(&vdeb
->hdl
, 2);
551 v4l2_ctrl_new_custom(&vdeb
->hdl
, &vimc_deb_ctrl_class
, NULL
);
552 v4l2_ctrl_new_custom(&vdeb
->hdl
, &vimc_deb_ctrl_mean_win_size
, NULL
);
553 vdeb
->sd
.ctrl_handler
= &vdeb
->hdl
;
554 if (vdeb
->hdl
.error
) {
555 ret
= vdeb
->hdl
.error
;
559 /* Initialize ved and sd */
560 vdeb
->pads
[0].flags
= MEDIA_PAD_FL_SINK
;
561 vdeb
->pads
[1].flags
= MEDIA_PAD_FL_SOURCE
;
563 ret
= vimc_ent_sd_register(&vdeb
->ved
, &vdeb
->sd
, v4l2_dev
,
565 MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV
, 2,
567 &vimc_deb_int_ops
, &vimc_deb_ops
);
571 vdeb
->ved
.process_frame
= vimc_deb_process_frame
;
572 vdeb
->ved
.dev
= &vimc
->pdev
.dev
;
573 vdeb
->mean_win_size
= vimc_deb_ctrl_mean_win_size
.def
;
575 /* Initialize the frame format */
576 vdeb
->sink_fmt
= sink_fmt_default
;
578 * TODO: Add support for more output formats, we only support
580 * NOTE: the src format is always the same as the sink, except
583 vdeb
->src_code
= MEDIA_BUS_FMT_RGB888_1X24
;
584 vdeb
->set_rgb_src
= vimc_deb_set_rgb_mbus_fmt_rgb888_1x24
;
589 v4l2_ctrl_handler_free(&vdeb
->hdl
);