2 * vimc-scaler.c Virtual Media Controller Driver
4 * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
18 #include <linux/component.h>
19 #include <linux/module.h>
20 #include <linux/mod_devicetable.h>
21 #include <linux/platform_device.h>
22 #include <linux/vmalloc.h>
23 #include <linux/v4l2-mediabus.h>
24 #include <media/v4l2-subdev.h>
26 #include "vimc-common.h"
28 #define VIMC_SCA_DRV_NAME "vimc-scaler"
30 static unsigned int sca_mult
= 3;
31 module_param(sca_mult
, uint
, 0000);
32 MODULE_PARM_DESC(sca_mult
, " the image size multiplier");
34 #define IS_SINK(pad) (!pad)
35 #define IS_SRC(pad) (pad)
38 struct vimc_sca_device
{
39 struct vimc_ent_device ved
;
40 struct v4l2_subdev sd
;
42 /* NOTE: the source fmt is the same as the sink
43 * with the width and hight multiplied by mult
45 struct v4l2_mbus_framefmt sink_fmt
;
46 /* Values calculated when the stream starts */
48 unsigned int src_line_size
;
52 static const struct v4l2_mbus_framefmt sink_fmt_default
= {
55 .code
= MEDIA_BUS_FMT_RGB888_1X24
,
56 .field
= V4L2_FIELD_NONE
,
57 .colorspace
= V4L2_COLORSPACE_DEFAULT
,
60 static int vimc_sca_init_cfg(struct v4l2_subdev
*sd
,
61 struct v4l2_subdev_pad_config
*cfg
)
63 struct v4l2_mbus_framefmt
*mf
;
66 mf
= v4l2_subdev_get_try_format(sd
, cfg
, 0);
67 *mf
= sink_fmt_default
;
69 for (i
= 1; i
< sd
->entity
.num_pads
; i
++) {
70 mf
= v4l2_subdev_get_try_format(sd
, cfg
, i
);
71 *mf
= sink_fmt_default
;
72 mf
->width
= mf
->width
* sca_mult
;
73 mf
->height
= mf
->height
* sca_mult
;
79 static int vimc_sca_enum_mbus_code(struct v4l2_subdev
*sd
,
80 struct v4l2_subdev_pad_config
*cfg
,
81 struct v4l2_subdev_mbus_code_enum
*code
)
83 const struct vimc_pix_map
*vpix
= vimc_pix_map_by_index(code
->index
);
85 /* We don't support bayer format */
86 if (!vpix
|| vpix
->bayer
)
89 code
->code
= vpix
->code
;
94 static int vimc_sca_enum_frame_size(struct v4l2_subdev
*sd
,
95 struct v4l2_subdev_pad_config
*cfg
,
96 struct v4l2_subdev_frame_size_enum
*fse
)
98 const struct vimc_pix_map
*vpix
;
103 /* Only accept code in the pix map table in non bayer format */
104 vpix
= vimc_pix_map_by_code(fse
->code
);
105 if (!vpix
|| vpix
->bayer
)
108 fse
->min_width
= VIMC_FRAME_MIN_WIDTH
;
109 fse
->min_height
= VIMC_FRAME_MIN_HEIGHT
;
111 if (IS_SINK(fse
->pad
)) {
112 fse
->max_width
= VIMC_FRAME_MAX_WIDTH
;
113 fse
->max_height
= VIMC_FRAME_MAX_HEIGHT
;
115 fse
->max_width
= VIMC_FRAME_MAX_WIDTH
* MAX_ZOOM
;
116 fse
->max_height
= VIMC_FRAME_MAX_HEIGHT
* MAX_ZOOM
;
122 static int vimc_sca_get_fmt(struct v4l2_subdev
*sd
,
123 struct v4l2_subdev_pad_config
*cfg
,
124 struct v4l2_subdev_format
*format
)
126 struct vimc_sca_device
*vsca
= v4l2_get_subdevdata(sd
);
128 /* Get the current sink format */
129 format
->format
= (format
->which
== V4L2_SUBDEV_FORMAT_TRY
) ?
130 *v4l2_subdev_get_try_format(sd
, cfg
, 0) :
133 /* Scale the frame size for the source pad */
134 if (IS_SRC(format
->pad
)) {
135 format
->format
.width
= vsca
->sink_fmt
.width
* sca_mult
;
136 format
->format
.height
= vsca
->sink_fmt
.height
* sca_mult
;
142 static void vimc_sca_adjust_sink_fmt(struct v4l2_mbus_framefmt
*fmt
)
144 const struct vimc_pix_map
*vpix
;
146 /* Only accept code in the pix map table in non bayer format */
147 vpix
= vimc_pix_map_by_code(fmt
->code
);
148 if (!vpix
|| vpix
->bayer
)
149 fmt
->code
= sink_fmt_default
.code
;
151 fmt
->width
= clamp_t(u32
, fmt
->width
, VIMC_FRAME_MIN_WIDTH
,
152 VIMC_FRAME_MAX_WIDTH
) & ~1;
153 fmt
->height
= clamp_t(u32
, fmt
->height
, VIMC_FRAME_MIN_HEIGHT
,
154 VIMC_FRAME_MAX_HEIGHT
) & ~1;
156 if (fmt
->field
== V4L2_FIELD_ANY
)
157 fmt
->field
= sink_fmt_default
.field
;
159 vimc_colorimetry_clamp(fmt
);
162 static int vimc_sca_set_fmt(struct v4l2_subdev
*sd
,
163 struct v4l2_subdev_pad_config
*cfg
,
164 struct v4l2_subdev_format
*fmt
)
166 struct vimc_sca_device
*vsca
= v4l2_get_subdevdata(sd
);
167 struct v4l2_mbus_framefmt
*sink_fmt
;
169 if (fmt
->which
== V4L2_SUBDEV_FORMAT_ACTIVE
) {
170 /* Do not change the format while stream is on */
174 sink_fmt
= &vsca
->sink_fmt
;
176 sink_fmt
= v4l2_subdev_get_try_format(sd
, cfg
, 0);
180 * Do not change the format of the source pad,
181 * it is propagated from the sink
183 if (IS_SRC(fmt
->pad
)) {
184 fmt
->format
= *sink_fmt
;
185 fmt
->format
.width
= sink_fmt
->width
* sca_mult
;
186 fmt
->format
.height
= sink_fmt
->height
* sca_mult
;
188 /* Set the new format in the sink pad */
189 vimc_sca_adjust_sink_fmt(&fmt
->format
);
191 dev_dbg(vsca
->dev
, "%s: sink format update: "
192 "old:%dx%d (0x%x, %d, %d, %d, %d) "
193 "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsca
->sd
.name
,
195 sink_fmt
->width
, sink_fmt
->height
, sink_fmt
->code
,
196 sink_fmt
->colorspace
, sink_fmt
->quantization
,
197 sink_fmt
->xfer_func
, sink_fmt
->ycbcr_enc
,
199 fmt
->format
.width
, fmt
->format
.height
, fmt
->format
.code
,
200 fmt
->format
.colorspace
, fmt
->format
.quantization
,
201 fmt
->format
.xfer_func
, fmt
->format
.ycbcr_enc
);
203 *sink_fmt
= fmt
->format
;
209 static const struct v4l2_subdev_pad_ops vimc_sca_pad_ops
= {
210 .init_cfg
= vimc_sca_init_cfg
,
211 .enum_mbus_code
= vimc_sca_enum_mbus_code
,
212 .enum_frame_size
= vimc_sca_enum_frame_size
,
213 .get_fmt
= vimc_sca_get_fmt
,
214 .set_fmt
= vimc_sca_set_fmt
,
217 static int vimc_sca_s_stream(struct v4l2_subdev
*sd
, int enable
)
219 struct vimc_sca_device
*vsca
= v4l2_get_subdevdata(sd
);
222 const struct vimc_pix_map
*vpix
;
223 unsigned int frame_size
;
228 /* Save the bytes per pixel of the sink */
229 vpix
= vimc_pix_map_by_code(vsca
->sink_fmt
.code
);
230 vsca
->bpp
= vpix
->bpp
;
232 /* Calculate the width in bytes of the src frame */
233 vsca
->src_line_size
= vsca
->sink_fmt
.width
*
234 sca_mult
* vsca
->bpp
;
236 /* Calculate the frame size of the source pad */
237 frame_size
= vsca
->src_line_size
* vsca
->sink_fmt
.height
*
240 /* Allocate the frame buffer. Use vmalloc to be able to
241 * allocate a large amount of memory
243 vsca
->src_frame
= vmalloc(frame_size
);
244 if (!vsca
->src_frame
)
248 if (!vsca
->src_frame
)
251 vfree(vsca
->src_frame
);
252 vsca
->src_frame
= NULL
;
258 static const struct v4l2_subdev_video_ops vimc_sca_video_ops
= {
259 .s_stream
= vimc_sca_s_stream
,
262 static const struct v4l2_subdev_ops vimc_sca_ops
= {
263 .pad
= &vimc_sca_pad_ops
,
264 .video
= &vimc_sca_video_ops
,
267 static void vimc_sca_fill_pix(u8
*const ptr
,
268 const u8
*const pixel
,
269 const unsigned int bpp
)
273 /* copy the pixel to the pointer */
274 for (i
= 0; i
< bpp
; i
++)
278 static void vimc_sca_scale_pix(const struct vimc_sca_device
*const vsca
,
279 const unsigned int lin
, const unsigned int col
,
280 const u8
*const sink_frame
)
282 unsigned int i
, j
, index
;
285 /* Point to the pixel value in position (lin, col) in the sink frame */
286 index
= VIMC_FRAME_INDEX(lin
, col
,
287 vsca
->sink_fmt
.width
,
289 pixel
= &sink_frame
[index
];
292 "sca: %s: --- scale_pix sink pos %dx%d, index %d ---\n",
293 vsca
->sd
.name
, lin
, col
, index
);
295 /* point to the place we are going to put the first pixel
296 * in the scaled src frame
298 index
= VIMC_FRAME_INDEX(lin
* sca_mult
, col
* sca_mult
,
299 vsca
->sink_fmt
.width
* sca_mult
, vsca
->bpp
);
301 dev_dbg(vsca
->dev
, "sca: %s: scale_pix src pos %dx%d, index %d\n",
302 vsca
->sd
.name
, lin
* sca_mult
, col
* sca_mult
, index
);
304 /* Repeat this pixel mult times */
305 for (i
= 0; i
< sca_mult
; i
++) {
306 /* Iterate through each beginning of a
307 * pixel repetition in a line
309 for (j
= 0; j
< sca_mult
* vsca
->bpp
; j
+= vsca
->bpp
) {
311 "sca: %s: sca: scale_pix src pos %d\n",
312 vsca
->sd
.name
, index
+ j
);
314 /* copy the pixel to the position index + j */
315 vimc_sca_fill_pix(&vsca
->src_frame
[index
+ j
],
319 /* move the index to the next line */
320 index
+= vsca
->src_line_size
;
324 static void vimc_sca_fill_src_frame(const struct vimc_sca_device
*const vsca
,
325 const u8
*const sink_frame
)
329 /* Scale each pixel from the original sink frame */
330 /* TODO: implement scale down, only scale up is supported for now */
331 for (i
= 0; i
< vsca
->sink_fmt
.height
; i
++)
332 for (j
= 0; j
< vsca
->sink_fmt
.width
; j
++)
333 vimc_sca_scale_pix(vsca
, i
, j
, sink_frame
);
336 static void *vimc_sca_process_frame(struct vimc_ent_device
*ved
,
337 const void *sink_frame
)
339 struct vimc_sca_device
*vsca
= container_of(ved
, struct vimc_sca_device
,
342 /* If the stream in this node is not active, just return */
343 if (!vsca
->src_frame
)
344 return ERR_PTR(-EINVAL
);
346 vimc_sca_fill_src_frame(vsca
, sink_frame
);
348 return vsca
->src_frame
;
351 static void vimc_sca_comp_unbind(struct device
*comp
, struct device
*master
,
354 struct vimc_ent_device
*ved
= dev_get_drvdata(comp
);
355 struct vimc_sca_device
*vsca
= container_of(ved
, struct vimc_sca_device
,
358 vimc_ent_sd_unregister(ved
, &vsca
->sd
);
363 static int vimc_sca_comp_bind(struct device
*comp
, struct device
*master
,
366 struct v4l2_device
*v4l2_dev
= master_data
;
367 struct vimc_platform_data
*pdata
= comp
->platform_data
;
368 struct vimc_sca_device
*vsca
;
371 /* Allocate the vsca struct */
372 vsca
= kzalloc(sizeof(*vsca
), GFP_KERNEL
);
376 /* Initialize ved and sd */
377 ret
= vimc_ent_sd_register(&vsca
->ved
, &vsca
->sd
, v4l2_dev
,
379 MEDIA_ENT_F_PROC_VIDEO_SCALER
, 2,
380 (const unsigned long[2]) {MEDIA_PAD_FL_SINK
,
381 MEDIA_PAD_FL_SOURCE
},
388 vsca
->ved
.process_frame
= vimc_sca_process_frame
;
389 dev_set_drvdata(comp
, &vsca
->ved
);
392 /* Initialize the frame format */
393 vsca
->sink_fmt
= sink_fmt_default
;
398 static const struct component_ops vimc_sca_comp_ops
= {
399 .bind
= vimc_sca_comp_bind
,
400 .unbind
= vimc_sca_comp_unbind
,
403 static int vimc_sca_probe(struct platform_device
*pdev
)
405 return component_add(&pdev
->dev
, &vimc_sca_comp_ops
);
408 static int vimc_sca_remove(struct platform_device
*pdev
)
410 component_del(&pdev
->dev
, &vimc_sca_comp_ops
);
415 static const struct platform_device_id vimc_sca_driver_ids
[] = {
417 .name
= VIMC_SCA_DRV_NAME
,
422 static struct platform_driver vimc_sca_pdrv
= {
423 .probe
= vimc_sca_probe
,
424 .remove
= vimc_sca_remove
,
425 .id_table
= vimc_sca_driver_ids
,
427 .name
= VIMC_SCA_DRV_NAME
,
431 module_platform_driver(vimc_sca_pdrv
);
433 MODULE_DEVICE_TABLE(platform
, vimc_sca_driver_ids
);
435 MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Scaler");
436 MODULE_AUTHOR("Helen Mae Koike Fornazier <helen.fornazier@gmail.com>");
437 MODULE_LICENSE("GPL");