media: atomisp: Add support for sensors which implement selection API / cropping
authorHans de Goede <hdegoede@redhat.com>
Mon, 29 May 2023 10:37:35 +0000 (11:37 +0100)
committerMauro Carvalho Chehab <mchehab@kernel.org>
Fri, 9 Jun 2023 14:31:38 +0000 (15:31 +0100)
Sensor drivers which implement set_selection V4L2_SEL_TGT_CROP expect
v4l2_subdev_state.pads[pad].try_crop to have valid contents when calling
set_fmt with which == V4L2_SUBDEV_FORMAT_TRY since the crop-rectangle
may influence the available image size.

Just passing an uninitalized struct v4l2_subdev_pad_config from
the stack to set_fmt with which == V4L2_SUBDEV_FORMAT_TRY will result
in wrong results with such drivers.

Store a per sensor v4l2_subdev_pad_config and add a new
atomisp_init_sensor_crop() function to initialize this before
registering /dev/* nodes with userspace.

Sensor drivers which implement the selection API will allow
the atomisp to properly deal with the extra padding the ISP wants
on a per sensor basis instead of hardcoding this.
atomisp_init_sensor_crop() stores the native and active rects
of the sensor in preparation for using these for this.

Link: https://lore.kernel.org/r/20230529103741.11904-16-hdegoede@redhat.com
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
drivers/staging/media/atomisp/pci/atomisp_cmd.c
drivers/staging/media/atomisp/pci/atomisp_internal.h
drivers/staging/media/atomisp/pci/atomisp_v4l2.c

index e17d057..4564b9a 100644 (file)
@@ -3698,9 +3698,8 @@ int atomisp_try_fmt(struct atomisp_device *isp, struct v4l2_pix_format *f,
        const struct atomisp_format_bridge *fmt, *snr_fmt;
        struct atomisp_sub_device *asd = &isp->asd;
        struct atomisp_input_subdev *input = &isp->inputs[asd->input_curr];
-       struct v4l2_subdev_pad_config pad_cfg;
        struct v4l2_subdev_state pad_state = {
-               .pads = &pad_cfg,
+               .pads = &input->pad_cfg,
        };
        struct v4l2_subdev_format format = {
                .which = V4L2_SUBDEV_FORMAT_TRY,
@@ -4164,9 +4163,8 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev, const struct v4l2_p
        struct atomisp_device *isp = asd->isp;
        struct atomisp_input_subdev *input = &isp->inputs[asd->input_curr];
        const struct atomisp_format_bridge *format;
-       struct v4l2_subdev_pad_config pad_cfg;
        struct v4l2_subdev_state pad_state = {
-               .pads = &pad_cfg,
+               .pads = &input->pad_cfg,
        };
        struct v4l2_subdev_format vformat = {
                .which = V4L2_SUBDEV_FORMAT_TRY,
index e59c0f1..14d21c6 100644 (file)
 struct atomisp_input_subdev {
        unsigned int type;
        enum atomisp_camera_port port;
+       bool crop_support;
        struct v4l2_subdev *camera;
+       /* Sensor rects for sensors which support crop */
+       struct v4l2_rect native_rect;
+       struct v4l2_rect active_rect;
+       /* Sensor pad_cfg for which == V4L2_SUBDEV_FORMAT_TRY calls */
+       struct v4l2_subdev_pad_config pad_cfg;
+
        struct v4l2_subdev *motor;
 
        /*
index a2ce9bb..506f04c 100644 (file)
@@ -931,6 +931,59 @@ v4l2_device_failed:
        return ret;
 }
 
+static void atomisp_init_sensor(struct atomisp_input_subdev *input)
+{
+       struct v4l2_subdev_state sd_state = {
+               .pads = &input->pad_cfg,
+       };
+       struct v4l2_subdev_selection sel = { };
+       int err;
+
+       sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+       sel.target = V4L2_SEL_TGT_NATIVE_SIZE;
+       err = v4l2_subdev_call(input->camera, pad, get_selection, NULL, &sel);
+       if (err)
+               return;
+
+       input->native_rect = sel.r;
+
+       sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+       sel.target = V4L2_SEL_TGT_CROP_DEFAULT;
+       err = v4l2_subdev_call(input->camera, pad, get_selection, NULL, &sel);
+       if (err)
+               return;
+
+       input->active_rect = sel.r;
+
+       /*
+        * The ISP also wants the non-active pixels at the border of the sensor
+        * for padding, set the crop rect to cover the entire sensor instead
+        * of only the default active area.
+        *
+        * Do this for both try and active formats since the try_crop rect in
+        * pad_cfg may influence (clamp) future try_fmt calls with which == try.
+        */
+       sel.which = V4L2_SUBDEV_FORMAT_TRY;
+       sel.target = V4L2_SEL_TGT_CROP;
+       sel.r = input->native_rect;
+       err = v4l2_subdev_call(input->camera, pad, set_selection, &sd_state, &sel);
+       if (err)
+               return;
+
+       sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+       sel.target = V4L2_SEL_TGT_CROP;
+       sel.r = input->native_rect;
+       err = v4l2_subdev_call(input->camera, pad, set_selection, NULL, &sel);
+       if (err)
+               return;
+
+       dev_info(input->camera->dev, "Supports crop native %dx%d active %dx%d\n",
+                input->native_rect.width, input->native_rect.height,
+                input->active_rect.width, input->active_rect.height);
+
+       input->crop_support = true;
+}
+
 int atomisp_register_device_nodes(struct atomisp_device *isp)
 {
        struct atomisp_input_subdev *input;
@@ -952,6 +1005,8 @@ int atomisp_register_device_nodes(struct atomisp_device *isp)
                input->port = i;
                input->camera = isp->sensor_subdevs[i];
 
+               atomisp_init_sensor(input);
+
                /*
                 * HACK: Currently VCM belongs to primary sensor only, but correct
                 * approach must be to acquire from platform code which sensor