Commit d321dd23 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab

media: imx: imx7-mipi-csis: Cleanup and fix subdev pad format handling

The subdev set pad format operation currently misbehaves in multiple ways:

- mipi_csis_try_format() unconditionally stores the format in the device
  state, even for V4L2_SUBDEV_FORMAT_TRY.

- The format is never stored in the pad cfg, but the pad cfg format
  always overwrites the format requested by the user.

- The sink format is not propagated to the source.

Fix all this by reworking the set format operation as follows:

1. For the source pad, turn set() into get() as the source format is not
   modifiable.
2. Validate the requested format and updated the stored format
   accordingly.
3. Return the format actually set.
4. Propagate the format from sink to source.
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: default avatarRui Miguel Silva <rmfrfs@gmail.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent 07f8f22a
......@@ -669,28 +669,6 @@ static int mipi_csis_init_cfg(struct v4l2_subdev *mipi_sd,
return 0;
}
static struct csis_pix_format const *
mipi_csis_try_format(struct v4l2_subdev *mipi_sd, struct v4l2_mbus_framefmt *mf)
{
struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
struct csis_pix_format const *csis_fmt;
csis_fmt = find_csis_format(mf->code);
if (!csis_fmt)
csis_fmt = &mipi_csis_formats[0];
v4l_bound_align_image(&mf->width, 1, CSIS_MAX_PIX_WIDTH,
csis_fmt->pix_width_alignment,
&mf->height, 1, CSIS_MAX_PIX_HEIGHT, 1,
0);
state->format_mbus.code = csis_fmt->code;
state->format_mbus.width = mf->width;
state->format_mbus.height = mf->height;
return csis_fmt;
}
static struct v4l2_mbus_framefmt *
mipi_csis_get_format(struct csi_state *state,
struct v4l2_subdev_pad_config *cfg,
......@@ -703,53 +681,67 @@ mipi_csis_get_format(struct csi_state *state,
return &state->format_mbus;
}
static int mipi_csis_set_fmt(struct v4l2_subdev *mipi_sd,
static int mipi_csis_get_fmt(struct v4l2_subdev *mipi_sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *sdformat)
{
struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
struct csis_pix_format const *csis_fmt;
struct v4l2_mbus_framefmt *fmt;
if (sdformat->pad >= CSIS_PADS_NUM)
return -EINVAL;
fmt = mipi_csis_get_format(state, cfg, sdformat->which, sdformat->pad);
mutex_lock(&state->lock);
if (sdformat->pad == CSIS_PAD_SOURCE) {
sdformat->format = *fmt;
goto unlock;
}
csis_fmt = mipi_csis_try_format(mipi_sd, &sdformat->format);
fmt = mipi_csis_get_format(state, cfg, sdformat->which, sdformat->pad);
sdformat->format = *fmt;
if (csis_fmt && sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
state->csis_fmt = csis_fmt;
else
cfg->try_fmt = sdformat->format;
unlock:
mutex_unlock(&state->lock);
return 0;
}
static int mipi_csis_get_fmt(struct v4l2_subdev *mipi_sd,
static int mipi_csis_set_fmt(struct v4l2_subdev *mipi_sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *sdformat)
{
struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
struct csis_pix_format const *csis_fmt;
struct v4l2_mbus_framefmt *fmt;
mutex_lock(&state->lock);
/*
* The CSIS can't transcode in any way, the source format can't be
* modified.
*/
if (sdformat->pad == CSIS_PAD_SOURCE)
return mipi_csis_get_fmt(mipi_sd, cfg, sdformat);
if (sdformat->pad != CSIS_PAD_SINK)
return -EINVAL;
fmt = mipi_csis_get_format(state, cfg, sdformat->which, sdformat->pad);
mutex_lock(&state->lock);
/* Validate the media bus code and clamp the size. */
csis_fmt = find_csis_format(sdformat->format.code);
if (!csis_fmt)
csis_fmt = &mipi_csis_formats[0];
fmt->code = csis_fmt->code;
fmt->width = sdformat->format.width;
fmt->height = sdformat->format.height;
v4l_bound_align_image(&fmt->width, 1, CSIS_MAX_PIX_WIDTH,
csis_fmt->pix_width_alignment,
&fmt->height, 1, CSIS_MAX_PIX_HEIGHT, 1, 0);
sdformat->format = *fmt;
/* Propagate the format from sink to source. */
fmt = mipi_csis_get_format(state, cfg, sdformat->which,
CSIS_PAD_SOURCE);
*fmt = sdformat->format;
/* Store the CSIS format descriptor for active formats. */
if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
state->csis_fmt = csis_fmt;
mutex_unlock(&state->lock);
return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment