]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/media/platform/vimc/vimc-scaler.c
Linux 5.6-rc7
[linux.git] / drivers / media / platform / vimc / vimc-scaler.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * vimc-scaler.c Virtual Media Controller Driver
4  *
5  * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
6  */
7
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>
13
14 #include "vimc-common.h"
15
16 static unsigned int sca_mult = 3;
17 module_param(sca_mult, uint, 0000);
18 MODULE_PARM_DESC(sca_mult, " the image size multiplier");
19
20 #define MAX_ZOOM        8
21
22 #define VIMC_SCA_FMT_WIDTH_DEFAULT  640
23 #define VIMC_SCA_FMT_HEIGHT_DEFAULT 480
24
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
30          */
31         struct v4l2_mbus_framefmt sink_fmt;
32         struct v4l2_rect crop_rect;
33         /* Values calculated when the stream starts */
34         u8 *src_frame;
35         unsigned int src_line_size;
36         unsigned int bpp;
37         struct media_pad pads[2];
38 };
39
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,
46 };
47
48 static const struct v4l2_rect crop_rect_default = {
49         .width = VIMC_SCA_FMT_WIDTH_DEFAULT,
50         .height = VIMC_SCA_FMT_HEIGHT_DEFAULT,
51         .top = 0,
52         .left = 0,
53 };
54
55 static const struct v4l2_rect crop_rect_min = {
56         .width = VIMC_FRAME_MIN_WIDTH,
57         .height = VIMC_FRAME_MIN_HEIGHT,
58         .top = 0,
59         .left = 0,
60 };
61
62 static struct v4l2_rect
63 vimc_sca_get_crop_bound_sink(const struct v4l2_mbus_framefmt *sink_fmt)
64 {
65         /* Get the crop bounds to clamp the crop rectangle correctly */
66         struct v4l2_rect r = {
67                 .left = 0,
68                 .top = 0,
69                 .width = sink_fmt->width,
70                 .height = sink_fmt->height,
71         };
72         return r;
73 }
74
75 static void vimc_sca_adjust_sink_crop(struct v4l2_rect *r,
76                                       const struct v4l2_mbus_framefmt *sink_fmt)
77 {
78         const struct v4l2_rect sink_rect =
79                 vimc_sca_get_crop_bound_sink(sink_fmt);
80
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);
84 }
85
86 static int vimc_sca_init_cfg(struct v4l2_subdev *sd,
87                              struct v4l2_subdev_pad_config *cfg)
88 {
89         struct v4l2_mbus_framefmt *mf;
90         struct v4l2_rect *r;
91         unsigned int i;
92
93         mf = v4l2_subdev_get_try_format(sd, cfg, 0);
94         *mf = sink_fmt_default;
95
96         r = v4l2_subdev_get_try_crop(sd, cfg, 0);
97         *r = crop_rect_default;
98
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;
104         }
105
106         return 0;
107 }
108
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)
112 {
113         const struct vimc_pix_map *vpix = vimc_pix_map_by_index(code->index);
114
115         /* We don't support bayer format */
116         if (!vpix || vpix->bayer)
117                 return -EINVAL;
118
119         code->code = vpix->code;
120
121         return 0;
122 }
123
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)
127 {
128         const struct vimc_pix_map *vpix;
129
130         if (fse->index)
131                 return -EINVAL;
132
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)
136                 return -EINVAL;
137
138         fse->min_width = VIMC_FRAME_MIN_WIDTH;
139         fse->min_height = VIMC_FRAME_MIN_HEIGHT;
140
141         if (VIMC_IS_SINK(fse->pad)) {
142                 fse->max_width = VIMC_FRAME_MAX_WIDTH;
143                 fse->max_height = VIMC_FRAME_MAX_HEIGHT;
144         } else {
145                 fse->max_width = VIMC_FRAME_MAX_WIDTH * MAX_ZOOM;
146                 fse->max_height = VIMC_FRAME_MAX_HEIGHT * MAX_ZOOM;
147         }
148
149         return 0;
150 }
151
152 static int vimc_sca_get_fmt(struct v4l2_subdev *sd,
153                             struct v4l2_subdev_pad_config *cfg,
154                             struct v4l2_subdev_format *format)
155 {
156         struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
157         struct v4l2_rect *crop_rect;
158
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);
163         } else {
164                 format->format = vsca->sink_fmt;
165                 crop_rect = &vsca->crop_rect;
166         }
167
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;
172         }
173
174         return 0;
175 }
176
177 static void vimc_sca_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt)
178 {
179         const struct vimc_pix_map *vpix;
180
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;
185
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;
190
191         if (fmt->field == V4L2_FIELD_ANY)
192                 fmt->field = sink_fmt_default.field;
193
194         vimc_colorimetry_clamp(fmt);
195 }
196
197 static int vimc_sca_set_fmt(struct v4l2_subdev *sd,
198                             struct v4l2_subdev_pad_config *cfg,
199                             struct v4l2_subdev_format *fmt)
200 {
201         struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
202         struct v4l2_mbus_framefmt *sink_fmt;
203         struct v4l2_rect *crop_rect;
204
205         if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
206                 /* Do not change the format while stream is on */
207                 if (vsca->src_frame)
208                         return -EBUSY;
209
210                 sink_fmt = &vsca->sink_fmt;
211                 crop_rect = &vsca->crop_rect;
212         } else {
213                 sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
214                 crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0);
215         }
216
217         /*
218          * Do not change the format of the source pad,
219          * it is propagated from the sink
220          */
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;
225         } else {
226                 /* Set the new format in the sink pad */
227                 vimc_sca_adjust_sink_fmt(&fmt->format);
228
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,
232                         /* old */
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,
236                         /* new */
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);
240
241                 *sink_fmt = fmt->format;
242
243                 /* Do the crop, but respect the current bounds */
244                 vimc_sca_adjust_sink_crop(crop_rect, sink_fmt);
245         }
246
247         return 0;
248 }
249
250 static int vimc_sca_get_selection(struct v4l2_subdev *sd,
251                                   struct v4l2_subdev_pad_config *cfg,
252                                   struct v4l2_subdev_selection *sel)
253 {
254         struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
255         struct v4l2_mbus_framefmt *sink_fmt;
256         struct v4l2_rect *crop_rect;
257
258         if (VIMC_IS_SRC(sel->pad))
259                 return -EINVAL;
260
261         if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
262                 sink_fmt = &vsca->sink_fmt;
263                 crop_rect = &vsca->crop_rect;
264         } else {
265                 sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
266                 crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0);
267         }
268
269         switch (sel->target) {
270         case V4L2_SEL_TGT_CROP:
271                 sel->r = *crop_rect;
272                 break;
273         case V4L2_SEL_TGT_CROP_BOUNDS:
274                 sel->r = vimc_sca_get_crop_bound_sink(sink_fmt);
275                 break;
276         default:
277                 return -EINVAL;
278         }
279
280         return 0;
281 }
282
283 static int vimc_sca_set_selection(struct v4l2_subdev *sd,
284                                   struct v4l2_subdev_pad_config *cfg,
285                                   struct v4l2_subdev_selection *sel)
286 {
287         struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
288         struct v4l2_mbus_framefmt *sink_fmt;
289         struct v4l2_rect *crop_rect;
290
291         if (VIMC_IS_SRC(sel->pad))
292                 return -EINVAL;
293
294         if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
295                 /* Do not change the format while stream is on */
296                 if (vsca->src_frame)
297                         return -EBUSY;
298
299                 crop_rect = &vsca->crop_rect;
300                 sink_fmt = &vsca->sink_fmt;
301         } else {
302                 crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0);
303                 sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
304         }
305
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);
310                 *crop_rect = sel->r;
311                 break;
312         default:
313                 return -EINVAL;
314         }
315
316         return 0;
317 }
318
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,
327 };
328
329 static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable)
330 {
331         struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
332
333         if (enable) {
334                 const struct vimc_pix_map *vpix;
335                 unsigned int frame_size;
336
337                 if (vsca->src_frame)
338                         return 0;
339
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;
343
344                 /* Calculate the width in bytes of the src frame */
345                 vsca->src_line_size = vsca->crop_rect.width *
346                                       sca_mult * vsca->bpp;
347
348                 /* Calculate the frame size of the source pad */
349                 frame_size = vsca->src_line_size * vsca->crop_rect.height *
350                              sca_mult;
351
352                 /* Allocate the frame buffer. Use vmalloc to be able to
353                  * allocate a large amount of memory
354                  */
355                 vsca->src_frame = vmalloc(frame_size);
356                 if (!vsca->src_frame)
357                         return -ENOMEM;
358
359         } else {
360                 if (!vsca->src_frame)
361                         return 0;
362
363                 vfree(vsca->src_frame);
364                 vsca->src_frame = NULL;
365         }
366
367         return 0;
368 }
369
370 static const struct v4l2_subdev_video_ops vimc_sca_video_ops = {
371         .s_stream = vimc_sca_s_stream,
372 };
373
374 static const struct v4l2_subdev_ops vimc_sca_ops = {
375         .pad = &vimc_sca_pad_ops,
376         .video = &vimc_sca_video_ops,
377 };
378
379 static void vimc_sca_fill_pix(u8 *const ptr,
380                               const u8 *const pixel,
381                               const unsigned int bpp)
382 {
383         unsigned int i;
384
385         /* copy the pixel to the pointer */
386         for (i = 0; i < bpp; i++)
387                 ptr[i] = pixel[i];
388 }
389
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)
393 {
394         const struct v4l2_rect crop_rect = vsca->crop_rect;
395         unsigned int i, j, index;
396         const u8 *pixel;
397
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,
401                                  vsca->bpp);
402         pixel = &sink_frame[index];
403
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);
407
408         /* point to the place we are going to put the first pixel
409          * in the scaled src frame
410          */
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);
415
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);
418
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
423                  */
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);
428
429                         /* copy the pixel to the position index + j */
430                         vimc_sca_fill_pix(&vsca->src_frame[index + j],
431                                           pixel, vsca->bpp);
432                 }
433
434                 /* move the index to the next line */
435                 index += vsca->src_line_size;
436         }
437 }
438
439 static void vimc_sca_fill_src_frame(const struct vimc_sca_device *const vsca,
440                                     const u8 *const sink_frame)
441 {
442         const struct v4l2_rect r = vsca->crop_rect;
443         unsigned int i, j;
444
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);
450 }
451
452 static void *vimc_sca_process_frame(struct vimc_ent_device *ved,
453                                     const void *sink_frame)
454 {
455         struct vimc_sca_device *vsca = container_of(ved, struct vimc_sca_device,
456                                                     ved);
457
458         /* If the stream in this node is not active, just return */
459         if (!vsca->src_frame)
460                 return ERR_PTR(-EINVAL);
461
462         vimc_sca_fill_src_frame(vsca, sink_frame);
463
464         return vsca->src_frame;
465 };
466
467 static void vimc_sca_release(struct v4l2_subdev *sd)
468 {
469         struct vimc_sca_device *vsca =
470                                 container_of(sd, struct vimc_sca_device, sd);
471
472         media_entity_cleanup(vsca->ved.ent);
473         kfree(vsca);
474 }
475
476 static const struct v4l2_subdev_internal_ops vimc_sca_int_ops = {
477         .release = vimc_sca_release,
478 };
479
480 void vimc_sca_rm(struct vimc_device *vimc, struct vimc_ent_device *ved)
481 {
482         struct vimc_sca_device *vsca;
483
484         vsca = container_of(ved, struct vimc_sca_device, ved);
485         v4l2_device_unregister_subdev(&vsca->sd);
486 }
487
488 struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc,
489                                      const char *vcfg_name)
490 {
491         struct v4l2_device *v4l2_dev = &vimc->v4l2_dev;
492         struct vimc_sca_device *vsca;
493         int ret;
494
495         /* Allocate the vsca struct */
496         vsca = kzalloc(sizeof(*vsca), GFP_KERNEL);
497         if (!vsca)
498                 return NULL;
499
500         /* Initialize ved and sd */
501         vsca->pads[0].flags = MEDIA_PAD_FL_SINK;
502         vsca->pads[1].flags = MEDIA_PAD_FL_SOURCE;
503
504         ret = vimc_ent_sd_register(&vsca->ved, &vsca->sd, v4l2_dev,
505                                    vcfg_name,
506                                    MEDIA_ENT_F_PROC_VIDEO_SCALER, 2,
507                                    vsca->pads,
508                                    &vimc_sca_int_ops, &vimc_sca_ops);
509         if (ret) {
510                 kfree(vsca);
511                 return NULL;
512         }
513
514         vsca->ved.process_frame = vimc_sca_process_frame;
515         vsca->ved.dev = &vimc->pdev.dev;
516
517         /* Initialize the frame format */
518         vsca->sink_fmt = sink_fmt_default;
519
520         /* Initialize the crop selection */
521         vsca->crop_rect = crop_rect_default;
522
523         return &vsca->ved;
524 }