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: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Rui Miguel Silva <rmfrfs@gmail.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
Laurent Pinchart 2020-03-13 00:47:09 +01:00 коммит произвёл Mauro Carvalho Chehab
Родитель 07f8f22a33
Коммит d321dd233b
1 изменённых файлов: 48 добавлений и 56 удалений

Просмотреть файл

@ -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,40 +681,6 @@ mipi_csis_get_format(struct csi_state *state,
return &state->format_mbus;
}
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;
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);
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,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *sdformat)
@ -745,11 +689,59 @@ static int mipi_csis_get_fmt(struct v4l2_subdev *mipi_sd,
struct v4l2_mbus_framefmt *fmt;
mutex_lock(&state->lock);
fmt = mipi_csis_get_format(state, cfg, sdformat->which, sdformat->pad);
sdformat->format = *fmt;
mutex_unlock(&state->lock);
return 0;
}
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;
/*
* 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;