^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * vimc-scaler.c Virtual Media Controller Driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/vmalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/v4l2-mediabus.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <media/v4l2-rect.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <media/v4l2-subdev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "vimc-common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) static unsigned int sca_mult = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) module_param(sca_mult, uint, 0000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) MODULE_PARM_DESC(sca_mult, " the image size multiplier");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define MAX_ZOOM 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define VIMC_SCA_FMT_WIDTH_DEFAULT 640
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define VIMC_SCA_FMT_HEIGHT_DEFAULT 480
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct vimc_sca_device {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) struct vimc_ent_device ved;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct v4l2_subdev sd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) /* NOTE: the source fmt is the same as the sink
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * with the width and hight multiplied by mult
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct v4l2_mbus_framefmt sink_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct v4l2_rect crop_rect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) /* Values calculated when the stream starts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) u8 *src_frame;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) unsigned int src_line_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) unsigned int bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct media_pad pads[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static const struct v4l2_mbus_framefmt sink_fmt_default = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) .width = VIMC_SCA_FMT_WIDTH_DEFAULT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) .height = VIMC_SCA_FMT_HEIGHT_DEFAULT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) .code = MEDIA_BUS_FMT_RGB888_1X24,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) .field = V4L2_FIELD_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) .colorspace = V4L2_COLORSPACE_SRGB,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static const struct v4l2_rect crop_rect_default = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) .width = VIMC_SCA_FMT_WIDTH_DEFAULT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) .height = VIMC_SCA_FMT_HEIGHT_DEFAULT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) .top = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) .left = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static const struct v4l2_rect crop_rect_min = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) .width = VIMC_FRAME_MIN_WIDTH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) .height = VIMC_FRAME_MIN_HEIGHT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) .top = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) .left = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static struct v4l2_rect
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) vimc_sca_get_crop_bound_sink(const struct v4l2_mbus_framefmt *sink_fmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /* Get the crop bounds to clamp the crop rectangle correctly */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) struct v4l2_rect r = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) .left = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) .top = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) .width = sink_fmt->width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) .height = sink_fmt->height,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static void vimc_sca_adjust_sink_crop(struct v4l2_rect *r,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) const struct v4l2_mbus_framefmt *sink_fmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) const struct v4l2_rect sink_rect =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) vimc_sca_get_crop_bound_sink(sink_fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /* Disallow rectangles smaller than the minimal one. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) v4l2_rect_set_min_size(r, &crop_rect_min);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) v4l2_rect_map_inside(r, &sink_rect);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) static int vimc_sca_init_cfg(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct v4l2_subdev_pad_config *cfg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) struct v4l2_mbus_framefmt *mf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct v4l2_rect *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) mf = v4l2_subdev_get_try_format(sd, cfg, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) *mf = sink_fmt_default;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) r = v4l2_subdev_get_try_crop(sd, cfg, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) *r = crop_rect_default;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) for (i = 1; i < sd->entity.num_pads; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) mf = v4l2_subdev_get_try_format(sd, cfg, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) *mf = sink_fmt_default;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) mf->width = mf->width * sca_mult;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) mf->height = mf->height * sca_mult;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static int vimc_sca_enum_mbus_code(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct v4l2_subdev_pad_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct v4l2_subdev_mbus_code_enum *code)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) u32 mbus_code = vimc_mbus_code_by_index(code->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) const struct vimc_pix_map *vpix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (!mbus_code)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) vpix = vimc_pix_map_by_code(mbus_code);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) /* We don't support bayer format */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (!vpix || vpix->bayer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) code->code = mbus_code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) static int vimc_sca_enum_frame_size(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct v4l2_subdev_pad_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) struct v4l2_subdev_frame_size_enum *fse)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) const struct vimc_pix_map *vpix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) if (fse->index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) /* Only accept code in the pix map table in non bayer format */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) vpix = vimc_pix_map_by_code(fse->code);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (!vpix || vpix->bayer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) fse->min_width = VIMC_FRAME_MIN_WIDTH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) fse->min_height = VIMC_FRAME_MIN_HEIGHT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (VIMC_IS_SINK(fse->pad)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) fse->max_width = VIMC_FRAME_MAX_WIDTH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) fse->max_height = VIMC_FRAME_MAX_HEIGHT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) fse->max_width = VIMC_FRAME_MAX_WIDTH * MAX_ZOOM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) fse->max_height = VIMC_FRAME_MAX_HEIGHT * MAX_ZOOM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) static int vimc_sca_get_fmt(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) struct v4l2_subdev_pad_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) struct v4l2_subdev_format *format)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) struct v4l2_rect *crop_rect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) /* Get the current sink format */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) format->format = *v4l2_subdev_get_try_format(sd, cfg, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) format->format = vsca->sink_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) crop_rect = &vsca->crop_rect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) /* Scale the frame size for the source pad */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (VIMC_IS_SRC(format->pad)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) format->format.width = crop_rect->width * sca_mult;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) format->format.height = crop_rect->height * sca_mult;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) static void vimc_sca_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) const struct vimc_pix_map *vpix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) /* Only accept code in the pix map table in non bayer format */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) vpix = vimc_pix_map_by_code(fmt->code);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (!vpix || vpix->bayer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) fmt->code = sink_fmt_default.code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) fmt->width = clamp_t(u32, fmt->width, VIMC_FRAME_MIN_WIDTH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) VIMC_FRAME_MAX_WIDTH) & ~1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) fmt->height = clamp_t(u32, fmt->height, VIMC_FRAME_MIN_HEIGHT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) VIMC_FRAME_MAX_HEIGHT) & ~1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (fmt->field == V4L2_FIELD_ANY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) fmt->field = sink_fmt_default.field;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) vimc_colorimetry_clamp(fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) static int vimc_sca_set_fmt(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) struct v4l2_subdev_pad_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) struct v4l2_subdev_format *fmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) struct v4l2_mbus_framefmt *sink_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) struct v4l2_rect *crop_rect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) /* Do not change the format while stream is on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (vsca->src_frame)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) sink_fmt = &vsca->sink_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) crop_rect = &vsca->crop_rect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) * Do not change the format of the source pad,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) * it is propagated from the sink
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (VIMC_IS_SRC(fmt->pad)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) fmt->format = *sink_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) fmt->format.width = crop_rect->width * sca_mult;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) fmt->format.height = crop_rect->height * sca_mult;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) /* Set the new format in the sink pad */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) vimc_sca_adjust_sink_fmt(&fmt->format);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) dev_dbg(vsca->ved.dev, "%s: sink format update: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) "old:%dx%d (0x%x, %d, %d, %d, %d) "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsca->sd.name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) /* old */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) sink_fmt->width, sink_fmt->height, sink_fmt->code,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) sink_fmt->colorspace, sink_fmt->quantization,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) sink_fmt->xfer_func, sink_fmt->ycbcr_enc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) /* new */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) fmt->format.width, fmt->format.height, fmt->format.code,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) fmt->format.colorspace, fmt->format.quantization,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) fmt->format.xfer_func, fmt->format.ycbcr_enc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) *sink_fmt = fmt->format;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) /* Do the crop, but respect the current bounds */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) vimc_sca_adjust_sink_crop(crop_rect, sink_fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) static int vimc_sca_get_selection(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) struct v4l2_subdev_pad_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) struct v4l2_subdev_selection *sel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) struct v4l2_mbus_framefmt *sink_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) struct v4l2_rect *crop_rect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) if (VIMC_IS_SRC(sel->pad))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) sink_fmt = &vsca->sink_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) crop_rect = &vsca->crop_rect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) switch (sel->target) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) case V4L2_SEL_TGT_CROP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) sel->r = *crop_rect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) case V4L2_SEL_TGT_CROP_BOUNDS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) sel->r = vimc_sca_get_crop_bound_sink(sink_fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) static int vimc_sca_set_selection(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) struct v4l2_subdev_pad_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) struct v4l2_subdev_selection *sel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) struct v4l2_mbus_framefmt *sink_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) struct v4l2_rect *crop_rect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) if (VIMC_IS_SRC(sel->pad))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) /* Do not change the format while stream is on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) if (vsca->src_frame)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) crop_rect = &vsca->crop_rect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) sink_fmt = &vsca->sink_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) switch (sel->target) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) case V4L2_SEL_TGT_CROP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) /* Do the crop, but respect the current bounds */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) vimc_sca_adjust_sink_crop(&sel->r, sink_fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) *crop_rect = sel->r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) static const struct v4l2_subdev_pad_ops vimc_sca_pad_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) .init_cfg = vimc_sca_init_cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) .enum_mbus_code = vimc_sca_enum_mbus_code,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) .enum_frame_size = vimc_sca_enum_frame_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) .get_fmt = vimc_sca_get_fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) .set_fmt = vimc_sca_set_fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) .get_selection = vimc_sca_get_selection,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) .set_selection = vimc_sca_set_selection,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) if (enable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) const struct vimc_pix_map *vpix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) unsigned int frame_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) if (vsca->src_frame)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) /* Save the bytes per pixel of the sink */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) vpix = vimc_pix_map_by_code(vsca->sink_fmt.code);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) vsca->bpp = vpix->bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) /* Calculate the width in bytes of the src frame */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) vsca->src_line_size = vsca->crop_rect.width *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) sca_mult * vsca->bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) /* Calculate the frame size of the source pad */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) frame_size = vsca->src_line_size * vsca->crop_rect.height *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) sca_mult;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) /* Allocate the frame buffer. Use vmalloc to be able to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) * allocate a large amount of memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) vsca->src_frame = vmalloc(frame_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) if (!vsca->src_frame)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) if (!vsca->src_frame)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) vfree(vsca->src_frame);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) vsca->src_frame = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) static const struct v4l2_subdev_video_ops vimc_sca_video_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) .s_stream = vimc_sca_s_stream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) static const struct v4l2_subdev_ops vimc_sca_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) .pad = &vimc_sca_pad_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) .video = &vimc_sca_video_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) static void vimc_sca_fill_pix(u8 *const ptr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) const u8 *const pixel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) const unsigned int bpp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) /* copy the pixel to the pointer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) for (i = 0; i < bpp; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) ptr[i] = pixel[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) static void vimc_sca_scale_pix(const struct vimc_sca_device *const vsca,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) unsigned int lin, unsigned int col,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) const u8 *const sink_frame)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) const struct v4l2_rect crop_rect = vsca->crop_rect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) unsigned int i, j, index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) const u8 *pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) /* Point to the pixel value in position (lin, col) in the sink frame */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) index = VIMC_FRAME_INDEX(lin, col,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) vsca->sink_fmt.width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) vsca->bpp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) pixel = &sink_frame[index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) dev_dbg(vsca->ved.dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) "sca: %s: --- scale_pix sink pos %dx%d, index %d ---\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) vsca->sd.name, lin, col, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) /* point to the place we are going to put the first pixel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) * in the scaled src frame
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) lin -= crop_rect.top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) col -= crop_rect.left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) index = VIMC_FRAME_INDEX(lin * sca_mult, col * sca_mult,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) crop_rect.width * sca_mult, vsca->bpp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) dev_dbg(vsca->ved.dev, "sca: %s: scale_pix src pos %dx%d, index %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) vsca->sd.name, lin * sca_mult, col * sca_mult, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) /* Repeat this pixel mult times */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) for (i = 0; i < sca_mult; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) /* Iterate through each beginning of a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) * pixel repetition in a line
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) for (j = 0; j < sca_mult * vsca->bpp; j += vsca->bpp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) dev_dbg(vsca->ved.dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) "sca: %s: sca: scale_pix src pos %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) vsca->sd.name, index + j);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) /* copy the pixel to the position index + j */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) vimc_sca_fill_pix(&vsca->src_frame[index + j],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) pixel, vsca->bpp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) /* move the index to the next line */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) index += vsca->src_line_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) static void vimc_sca_fill_src_frame(const struct vimc_sca_device *const vsca,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) const u8 *const sink_frame)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) const struct v4l2_rect r = vsca->crop_rect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) unsigned int i, j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) /* Scale each pixel from the original sink frame */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) /* TODO: implement scale down, only scale up is supported for now */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) for (i = r.top; i < r.top + r.height; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) for (j = r.left; j < r.left + r.width; j++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) vimc_sca_scale_pix(vsca, i, j, sink_frame);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) static void *vimc_sca_process_frame(struct vimc_ent_device *ved,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) const void *sink_frame)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) struct vimc_sca_device *vsca = container_of(ved, struct vimc_sca_device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) ved);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) /* If the stream in this node is not active, just return */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) if (!vsca->src_frame)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) vimc_sca_fill_src_frame(vsca, sink_frame);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) return vsca->src_frame;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) static void vimc_sca_release(struct vimc_ent_device *ved)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) struct vimc_sca_device *vsca =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) container_of(ved, struct vimc_sca_device, ved);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) media_entity_cleanup(vsca->ved.ent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) kfree(vsca);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) static struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) const char *vcfg_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) struct v4l2_device *v4l2_dev = &vimc->v4l2_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) struct vimc_sca_device *vsca;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) /* Allocate the vsca struct */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) vsca = kzalloc(sizeof(*vsca), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) if (!vsca)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) /* Initialize ved and sd */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) vsca->pads[0].flags = MEDIA_PAD_FL_SINK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) vsca->pads[1].flags = MEDIA_PAD_FL_SOURCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) ret = vimc_ent_sd_register(&vsca->ved, &vsca->sd, v4l2_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) vcfg_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) MEDIA_ENT_F_PROC_VIDEO_SCALER, 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) vsca->pads, &vimc_sca_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) kfree(vsca);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) return ERR_PTR(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) vsca->ved.process_frame = vimc_sca_process_frame;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) vsca->ved.dev = vimc->mdev.dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) /* Initialize the frame format */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) vsca->sink_fmt = sink_fmt_default;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) /* Initialize the crop selection */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) vsca->crop_rect = crop_rect_default;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) return &vsca->ved;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) struct vimc_ent_type vimc_sca_type = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) .add = vimc_sca_add,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) .release = vimc_sca_release
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) };