1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * vimc-scaler.c Virtual Media Controller Driver
5 * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
8 #include <linux/moduleparam.h>
9 #include <linux/vmalloc.h>
10 #include <linux/v4l2-mediabus.h>
11 #include <media/v4l2-rect.h>
12 #include <media/v4l2-subdev.h>
14 #include "vimc-common.h"
16 static unsigned int sca_mult
= 3;
17 module_param(sca_mult
, uint
, 0000);
18 MODULE_PARM_DESC(sca_mult
, " the image size multiplier");
22 #define VIMC_SCA_FMT_WIDTH_DEFAULT 640
23 #define VIMC_SCA_FMT_HEIGHT_DEFAULT 480
25 struct vimc_sca_device
{
26 struct vimc_ent_device ved
;
27 struct v4l2_subdev sd
;
28 /* NOTE: the source fmt is the same as the sink
29 * with the width and hight multiplied by mult
31 struct v4l2_mbus_framefmt sink_fmt
;
32 struct v4l2_rect crop_rect
;
33 /* Values calculated when the stream starts */
35 unsigned int src_line_size
;
37 struct media_pad pads
[2];
40 static const struct v4l2_mbus_framefmt sink_fmt_default
= {
41 .width
= VIMC_SCA_FMT_WIDTH_DEFAULT
,
42 .height
= VIMC_SCA_FMT_HEIGHT_DEFAULT
,
43 .code
= MEDIA_BUS_FMT_RGB888_1X24
,
44 .field
= V4L2_FIELD_NONE
,
45 .colorspace
= V4L2_COLORSPACE_DEFAULT
,
48 static const struct v4l2_rect crop_rect_default
= {
49 .width
= VIMC_SCA_FMT_WIDTH_DEFAULT
,
50 .height
= VIMC_SCA_FMT_HEIGHT_DEFAULT
,
55 static const struct v4l2_rect crop_rect_min
= {
56 .width
= VIMC_FRAME_MIN_WIDTH
,
57 .height
= VIMC_FRAME_MIN_HEIGHT
,
62 static struct v4l2_rect
63 vimc_sca_get_crop_bound_sink(const struct v4l2_mbus_framefmt
*sink_fmt
)
65 /* Get the crop bounds to clamp the crop rectangle correctly */
66 struct v4l2_rect r
= {
69 .width
= sink_fmt
->width
,
70 .height
= sink_fmt
->height
,
75 static void vimc_sca_adjust_sink_crop(struct v4l2_rect
*r
,
76 const struct v4l2_mbus_framefmt
*sink_fmt
)
78 const struct v4l2_rect sink_rect
=
79 vimc_sca_get_crop_bound_sink(sink_fmt
);
81 /* Disallow rectangles smaller than the minimal one. */
82 v4l2_rect_set_min_size(r
, &crop_rect_min
);
83 v4l2_rect_map_inside(r
, &sink_rect
);
86 static int vimc_sca_init_cfg(struct v4l2_subdev
*sd
,
87 struct v4l2_subdev_pad_config
*cfg
)
89 struct v4l2_mbus_framefmt
*mf
;
93 mf
= v4l2_subdev_get_try_format(sd
, cfg
, 0);
94 *mf
= sink_fmt_default
;
96 r
= v4l2_subdev_get_try_crop(sd
, cfg
, 0);
97 *r
= crop_rect_default
;
99 for (i
= 1; i
< sd
->entity
.num_pads
; i
++) {
100 mf
= v4l2_subdev_get_try_format(sd
, cfg
, i
);
101 *mf
= sink_fmt_default
;
102 mf
->width
= mf
->width
* sca_mult
;
103 mf
->height
= mf
->height
* sca_mult
;
109 static int vimc_sca_enum_mbus_code(struct v4l2_subdev
*sd
,
110 struct v4l2_subdev_pad_config
*cfg
,
111 struct v4l2_subdev_mbus_code_enum
*code
)
113 const struct vimc_pix_map
*vpix
= vimc_pix_map_by_index(code
->index
);
115 /* We don't support bayer format */
116 if (!vpix
|| vpix
->bayer
)
119 code
->code
= vpix
->code
;
124 static int vimc_sca_enum_frame_size(struct v4l2_subdev
*sd
,
125 struct v4l2_subdev_pad_config
*cfg
,
126 struct v4l2_subdev_frame_size_enum
*fse
)
128 const struct vimc_pix_map
*vpix
;
133 /* Only accept code in the pix map table in non bayer format */
134 vpix
= vimc_pix_map_by_code(fse
->code
);
135 if (!vpix
|| vpix
->bayer
)
138 fse
->min_width
= VIMC_FRAME_MIN_WIDTH
;
139 fse
->min_height
= VIMC_FRAME_MIN_HEIGHT
;
141 if (VIMC_IS_SINK(fse
->pad
)) {
142 fse
->max_width
= VIMC_FRAME_MAX_WIDTH
;
143 fse
->max_height
= VIMC_FRAME_MAX_HEIGHT
;
145 fse
->max_width
= VIMC_FRAME_MAX_WIDTH
* MAX_ZOOM
;
146 fse
->max_height
= VIMC_FRAME_MAX_HEIGHT
* MAX_ZOOM
;
152 static int vimc_sca_get_fmt(struct v4l2_subdev
*sd
,
153 struct v4l2_subdev_pad_config
*cfg
,
154 struct v4l2_subdev_format
*format
)
156 struct vimc_sca_device
*vsca
= v4l2_get_subdevdata(sd
);
157 struct v4l2_rect
*crop_rect
;
159 /* Get the current sink format */
160 if (format
->which
== V4L2_SUBDEV_FORMAT_TRY
) {
161 format
->format
= *v4l2_subdev_get_try_format(sd
, cfg
, 0);
162 crop_rect
= v4l2_subdev_get_try_crop(sd
, cfg
, 0);
164 format
->format
= vsca
->sink_fmt
;
165 crop_rect
= &vsca
->crop_rect
;
168 /* Scale the frame size for the source pad */
169 if (VIMC_IS_SRC(format
->pad
)) {
170 format
->format
.width
= crop_rect
->width
* sca_mult
;
171 format
->format
.height
= crop_rect
->height
* sca_mult
;
177 static void vimc_sca_adjust_sink_fmt(struct v4l2_mbus_framefmt
*fmt
)
179 const struct vimc_pix_map
*vpix
;
181 /* Only accept code in the pix map table in non bayer format */
182 vpix
= vimc_pix_map_by_code(fmt
->code
);
183 if (!vpix
|| vpix
->bayer
)
184 fmt
->code
= sink_fmt_default
.code
;
186 fmt
->width
= clamp_t(u32
, fmt
->width
, VIMC_FRAME_MIN_WIDTH
,
187 VIMC_FRAME_MAX_WIDTH
) & ~1;
188 fmt
->height
= clamp_t(u32
, fmt
->height
, VIMC_FRAME_MIN_HEIGHT
,
189 VIMC_FRAME_MAX_HEIGHT
) & ~1;
191 if (fmt
->field
== V4L2_FIELD_ANY
)
192 fmt
->field
= sink_fmt_default
.field
;
194 vimc_colorimetry_clamp(fmt
);
197 static int vimc_sca_set_fmt(struct v4l2_subdev
*sd
,
198 struct v4l2_subdev_pad_config
*cfg
,
199 struct v4l2_subdev_format
*fmt
)
201 struct vimc_sca_device
*vsca
= v4l2_get_subdevdata(sd
);
202 struct v4l2_mbus_framefmt
*sink_fmt
;
203 struct v4l2_rect
*crop_rect
;
205 if (fmt
->which
== V4L2_SUBDEV_FORMAT_ACTIVE
) {
206 /* Do not change the format while stream is on */
210 sink_fmt
= &vsca
->sink_fmt
;
211 crop_rect
= &vsca
->crop_rect
;
213 sink_fmt
= v4l2_subdev_get_try_format(sd
, cfg
, 0);
214 crop_rect
= v4l2_subdev_get_try_crop(sd
, cfg
, 0);
218 * Do not change the format of the source pad,
219 * it is propagated from the sink
221 if (VIMC_IS_SRC(fmt
->pad
)) {
222 fmt
->format
= *sink_fmt
;
223 fmt
->format
.width
= crop_rect
->width
* sca_mult
;
224 fmt
->format
.height
= crop_rect
->height
* sca_mult
;
226 /* Set the new format in the sink pad */
227 vimc_sca_adjust_sink_fmt(&fmt
->format
);
229 dev_dbg(vsca
->ved
.dev
, "%s: sink format update: "
230 "old:%dx%d (0x%x, %d, %d, %d, %d) "
231 "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsca
->sd
.name
,
233 sink_fmt
->width
, sink_fmt
->height
, sink_fmt
->code
,
234 sink_fmt
->colorspace
, sink_fmt
->quantization
,
235 sink_fmt
->xfer_func
, sink_fmt
->ycbcr_enc
,
237 fmt
->format
.width
, fmt
->format
.height
, fmt
->format
.code
,
238 fmt
->format
.colorspace
, fmt
->format
.quantization
,
239 fmt
->format
.xfer_func
, fmt
->format
.ycbcr_enc
);
241 *sink_fmt
= fmt
->format
;
243 /* Do the crop, but respect the current bounds */
244 vimc_sca_adjust_sink_crop(crop_rect
, sink_fmt
);
250 static int vimc_sca_get_selection(struct v4l2_subdev
*sd
,
251 struct v4l2_subdev_pad_config
*cfg
,
252 struct v4l2_subdev_selection
*sel
)
254 struct vimc_sca_device
*vsca
= v4l2_get_subdevdata(sd
);
255 struct v4l2_mbus_framefmt
*sink_fmt
;
256 struct v4l2_rect
*crop_rect
;
258 if (VIMC_IS_SRC(sel
->pad
))
261 if (sel
->which
== V4L2_SUBDEV_FORMAT_ACTIVE
) {
262 sink_fmt
= &vsca
->sink_fmt
;
263 crop_rect
= &vsca
->crop_rect
;
265 sink_fmt
= v4l2_subdev_get_try_format(sd
, cfg
, 0);
266 crop_rect
= v4l2_subdev_get_try_crop(sd
, cfg
, 0);
269 switch (sel
->target
) {
270 case V4L2_SEL_TGT_CROP
:
273 case V4L2_SEL_TGT_CROP_BOUNDS
:
274 sel
->r
= vimc_sca_get_crop_bound_sink(sink_fmt
);
283 static int vimc_sca_set_selection(struct v4l2_subdev
*sd
,
284 struct v4l2_subdev_pad_config
*cfg
,
285 struct v4l2_subdev_selection
*sel
)
287 struct vimc_sca_device
*vsca
= v4l2_get_subdevdata(sd
);
288 struct v4l2_mbus_framefmt
*sink_fmt
;
289 struct v4l2_rect
*crop_rect
;
291 if (VIMC_IS_SRC(sel
->pad
))
294 if (sel
->which
== V4L2_SUBDEV_FORMAT_ACTIVE
) {
295 /* Do not change the format while stream is on */
299 crop_rect
= &vsca
->crop_rect
;
300 sink_fmt
= &vsca
->sink_fmt
;
302 crop_rect
= v4l2_subdev_get_try_crop(sd
, cfg
, 0);
303 sink_fmt
= v4l2_subdev_get_try_format(sd
, cfg
, 0);
306 switch (sel
->target
) {
307 case V4L2_SEL_TGT_CROP
:
308 /* Do the crop, but respect the current bounds */
309 vimc_sca_adjust_sink_crop(&sel
->r
, sink_fmt
);
319 static const struct v4l2_subdev_pad_ops vimc_sca_pad_ops
= {
320 .init_cfg
= vimc_sca_init_cfg
,
321 .enum_mbus_code
= vimc_sca_enum_mbus_code
,
322 .enum_frame_size
= vimc_sca_enum_frame_size
,
323 .get_fmt
= vimc_sca_get_fmt
,
324 .set_fmt
= vimc_sca_set_fmt
,
325 .get_selection
= vimc_sca_get_selection
,
326 .set_selection
= vimc_sca_set_selection
,
329 static int vimc_sca_s_stream(struct v4l2_subdev
*sd
, int enable
)
331 struct vimc_sca_device
*vsca
= v4l2_get_subdevdata(sd
);
334 const struct vimc_pix_map
*vpix
;
335 unsigned int frame_size
;
340 /* Save the bytes per pixel of the sink */
341 vpix
= vimc_pix_map_by_code(vsca
->sink_fmt
.code
);
342 vsca
->bpp
= vpix
->bpp
;
344 /* Calculate the width in bytes of the src frame */
345 vsca
->src_line_size
= vsca
->crop_rect
.width
*
346 sca_mult
* vsca
->bpp
;
348 /* Calculate the frame size of the source pad */
349 frame_size
= vsca
->src_line_size
* vsca
->crop_rect
.height
*
352 /* Allocate the frame buffer. Use vmalloc to be able to
353 * allocate a large amount of memory
355 vsca
->src_frame
= vmalloc(frame_size
);
356 if (!vsca
->src_frame
)
360 if (!vsca
->src_frame
)
363 vfree(vsca
->src_frame
);
364 vsca
->src_frame
= NULL
;
370 static const struct v4l2_subdev_video_ops vimc_sca_video_ops
= {
371 .s_stream
= vimc_sca_s_stream
,
374 static const struct v4l2_subdev_ops vimc_sca_ops
= {
375 .pad
= &vimc_sca_pad_ops
,
376 .video
= &vimc_sca_video_ops
,
379 static void vimc_sca_fill_pix(u8
*const ptr
,
380 const u8
*const pixel
,
381 const unsigned int bpp
)
385 /* copy the pixel to the pointer */
386 for (i
= 0; i
< bpp
; i
++)
390 static void vimc_sca_scale_pix(const struct vimc_sca_device
*const vsca
,
391 unsigned int lin
, unsigned int col
,
392 const u8
*const sink_frame
)
394 const struct v4l2_rect crop_rect
= vsca
->crop_rect
;
395 unsigned int i
, j
, index
;
398 /* Point to the pixel value in position (lin, col) in the sink frame */
399 index
= VIMC_FRAME_INDEX(lin
, col
,
400 vsca
->sink_fmt
.width
,
402 pixel
= &sink_frame
[index
];
404 dev_dbg(vsca
->ved
.dev
,
405 "sca: %s: --- scale_pix sink pos %dx%d, index %d ---\n",
406 vsca
->sd
.name
, lin
, col
, index
);
408 /* point to the place we are going to put the first pixel
409 * in the scaled src frame
411 lin
-= crop_rect
.top
;
412 col
-= crop_rect
.left
;
413 index
= VIMC_FRAME_INDEX(lin
* sca_mult
, col
* sca_mult
,
414 crop_rect
.width
* sca_mult
, vsca
->bpp
);
416 dev_dbg(vsca
->ved
.dev
, "sca: %s: scale_pix src pos %dx%d, index %d\n",
417 vsca
->sd
.name
, lin
* sca_mult
, col
* sca_mult
, index
);
419 /* Repeat this pixel mult times */
420 for (i
= 0; i
< sca_mult
; i
++) {
421 /* Iterate through each beginning of a
422 * pixel repetition in a line
424 for (j
= 0; j
< sca_mult
* vsca
->bpp
; j
+= vsca
->bpp
) {
425 dev_dbg(vsca
->ved
.dev
,
426 "sca: %s: sca: scale_pix src pos %d\n",
427 vsca
->sd
.name
, index
+ j
);
429 /* copy the pixel to the position index + j */
430 vimc_sca_fill_pix(&vsca
->src_frame
[index
+ j
],
434 /* move the index to the next line */
435 index
+= vsca
->src_line_size
;
439 static void vimc_sca_fill_src_frame(const struct vimc_sca_device
*const vsca
,
440 const u8
*const sink_frame
)
442 const struct v4l2_rect r
= vsca
->crop_rect
;
445 /* Scale each pixel from the original sink frame */
446 /* TODO: implement scale down, only scale up is supported for now */
447 for (i
= r
.top
; i
< r
.top
+ r
.height
; i
++)
448 for (j
= r
.left
; j
< r
.left
+ r
.width
; j
++)
449 vimc_sca_scale_pix(vsca
, i
, j
, sink_frame
);
452 static void *vimc_sca_process_frame(struct vimc_ent_device
*ved
,
453 const void *sink_frame
)
455 struct vimc_sca_device
*vsca
= container_of(ved
, struct vimc_sca_device
,
458 /* If the stream in this node is not active, just return */
459 if (!vsca
->src_frame
)
460 return ERR_PTR(-EINVAL
);
462 vimc_sca_fill_src_frame(vsca
, sink_frame
);
464 return vsca
->src_frame
;
467 void vimc_sca_release(struct vimc_ent_device
*ved
)
469 struct vimc_sca_device
*vsca
=
470 container_of(ved
, struct vimc_sca_device
, ved
);
472 media_entity_cleanup(vsca
->ved
.ent
);
476 struct vimc_ent_device
*vimc_sca_add(struct vimc_device
*vimc
,
477 const char *vcfg_name
)
479 struct v4l2_device
*v4l2_dev
= &vimc
->v4l2_dev
;
480 struct vimc_sca_device
*vsca
;
483 /* Allocate the vsca struct */
484 vsca
= kzalloc(sizeof(*vsca
), GFP_KERNEL
);
488 /* Initialize ved and sd */
489 vsca
->pads
[0].flags
= MEDIA_PAD_FL_SINK
;
490 vsca
->pads
[1].flags
= MEDIA_PAD_FL_SOURCE
;
492 ret
= vimc_ent_sd_register(&vsca
->ved
, &vsca
->sd
, v4l2_dev
,
494 MEDIA_ENT_F_PROC_VIDEO_SCALER
, 2,
495 vsca
->pads
, &vimc_sca_ops
);
501 vsca
->ved
.process_frame
= vimc_sca_process_frame
;
502 vsca
->ved
.dev
= vimc
->mdev
.dev
;
504 /* Initialize the frame format */
505 vsca
->sink_fmt
= sink_fmt_default
;
507 /* Initialize the crop selection */
508 vsca
->crop_rect
= crop_rect_default
;