The try_fmt was not actually trying out the provided format
but merely returning the current format basically like get_fmt.
In addition set_fmt should first invoked try_fmt to validate the
given format before applying it to the hardware.

To fix all of these the whole get/try/set ioctl functions had to
be reworked.
When calculating the bytesperline/stride and sizeimage format
member we don't need to locally store the current value of
bytesperpixel as it can easily get derived dynamically.

Signed-off-by: Benoit Parrot <[email protected]>
---
 drivers/media/platform/am437x/am437x-vpfe.c | 334 +++++++++-----------
 drivers/media/platform/am437x/am437x-vpfe.h |   2 -
 2 files changed, 155 insertions(+), 181 deletions(-)

diff --git a/drivers/media/platform/am437x/am437x-vpfe.c 
b/drivers/media/platform/am437x/am437x-vpfe.c
index 4fb9c8ed7e92..9759ed398943 100644
--- a/drivers/media/platform/am437x/am437x-vpfe.c
+++ b/drivers/media/platform/am437x/am437x-vpfe.c
@@ -143,9 +143,11 @@ static struct vpfe_fmt formats[] = {
        },
 };
 
-static int
-__vpfe_get_format(struct vpfe_device *vpfe,
-                 struct v4l2_format *format, unsigned int *bpp);
+static int __subdev_get_format(struct vpfe_device *vpfe,
+                              struct v4l2_mbus_framefmt *fmt);
+static int vpfe_calc_format_size(struct vpfe_device *vpfe,
+                                const struct vpfe_fmt *fmt,
+                                struct v4l2_format *f);
 
 static const struct vpfe_fmt *find_format_by_code(struct vpfe_device *vpfe,
                                                  unsigned int code)
@@ -177,62 +179,16 @@ static const struct vpfe_fmt *find_format_by_pix(struct 
vpfe_device *vpfe,
        return NULL;
 }
 
-static void
-mbus_to_pix(struct vpfe_device *vpfe,
-           const struct v4l2_mbus_framefmt *mbus,
-           struct v4l2_pix_format *pix, unsigned int *bpp)
+static unsigned int __get_bytesperpixel(struct vpfe_device *vpfe,
+                                       const struct vpfe_fmt *fmt)
 {
        struct vpfe_subdev_info *sdinfo = vpfe->current_subdev;
        unsigned int bus_width = sdinfo->vpfe_param.bus_width;
-       const struct vpfe_fmt *fmt;
-
-       fmt = find_format_by_code(vpfe, mbus->code);
-       if (WARN_ON(fmt == NULL)) {
-               pr_err("Invalid mbus code set\n");
-               *bpp = 1;
-               return;
-       }
+       u32 bpp;
 
-       memset(pix, 0, sizeof(*pix));
-       v4l2_fill_pix_format(pix, mbus);
-       pix->pixelformat = fmt->fourcc;
-       *bpp = (bus_width == 10) ?  fmt->l.bpp : fmt->s.bpp;
+       bpp = (bus_width == 10) ? fmt->l.bpp : fmt->s.bpp;
 
-       /* pitch should be 32 bytes aligned */
-       pix->bytesperline = ALIGN(pix->width * *bpp, 32);
-       pix->sizeimage = pix->bytesperline * pix->height;
-}
-
-static void pix_to_mbus(struct vpfe_device *vpfe,
-                       struct v4l2_pix_format *pix_fmt,
-                       struct v4l2_mbus_framefmt *mbus_fmt)
-{
-       const struct vpfe_fmt *fmt;
-
-       fmt = find_format_by_pix(vpfe, pix_fmt->pixelformat);
-       if (!fmt) {
-               /* default to first entry */
-               vpfe_dbg(3, vpfe, "Invalid pixel code: %x, default used 
instead\n",
-                       pix_fmt->pixelformat);
-               fmt = vpfe->active_fmt[0];
-       }
-
-       memset(mbus_fmt, 0, sizeof(*mbus_fmt));
-       v4l2_fill_mbus_format(mbus_fmt, pix_fmt, fmt->code);
-}
-
-static int
-cmp_v4l2_format(const struct v4l2_format *lhs, const struct v4l2_format *rhs)
-{
-       return lhs->type == rhs->type &&
-               lhs->fmt.pix.width == rhs->fmt.pix.width &&
-               lhs->fmt.pix.height == rhs->fmt.pix.height &&
-               lhs->fmt.pix.pixelformat == rhs->fmt.pix.pixelformat &&
-               lhs->fmt.pix.field == rhs->fmt.pix.field &&
-               lhs->fmt.pix.colorspace == rhs->fmt.pix.colorspace &&
-               lhs->fmt.pix.ycbcr_enc == rhs->fmt.pix.ycbcr_enc &&
-               lhs->fmt.pix.quantization == rhs->fmt.pix.quantization &&
-               lhs->fmt.pix.xfer_func == rhs->fmt.pix.xfer_func;
+       return bpp;
 }
 
 static inline u32 vpfe_reg_read(struct vpfe_ccdc *ccdc, u32 offset)
@@ -971,6 +927,7 @@ static int vpfe_get_ccdc_image_format(struct vpfe_device 
*vpfe,
 static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe)
 {
        enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED;
+       u32 bpp;
        int ret = 0;
 
        vpfe_dbg(2, vpfe, "%s:\n", __func__);
@@ -985,7 +942,8 @@ static int vpfe_config_ccdc_image_format(struct vpfe_device 
*vpfe)
        }
 
        /* configure the image window */
-       vpfe_ccdc_set_image_window(&vpfe->ccdc, &vpfe->crop, vpfe->bpp);
+       bpp = __get_bytesperpixel(vpfe, vpfe->fmt);
+       vpfe_ccdc_set_image_window(&vpfe->ccdc, &vpfe->crop, bpp);
 
        switch (vpfe->v_fmt.fmt.pix.field) {
        case V4L2_FIELD_INTERLACED:
@@ -1030,7 +988,7 @@ static int vpfe_config_image_format(struct vpfe_device 
*vpfe,
                                    v4l2_std_id std_id)
 {
        const struct vpfe_fmt *fmt;
-       struct v4l2_pix_format *pix = &vpfe->v_fmt.fmt.pix;
+       struct v4l2_mbus_framefmt mbus_fmt;
        int i, ret;
 
        for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) {
@@ -1052,34 +1010,29 @@ static int vpfe_config_image_format(struct vpfe_device 
*vpfe,
                return -EINVAL;
        }
 
-       vpfe->crop.top = vpfe->crop.left = 0;
-       vpfe->crop.width = vpfe->std_info.active_pixels;
-       vpfe->crop.height = vpfe->std_info.active_lines;
-       pix->width = vpfe->crop.width;
-       pix->height = vpfe->crop.height;
-       pix->pixelformat = V4L2_PIX_FMT_YUYV;
-
-       /* first field and frame format based on standard frame format */
-       if (vpfe->std_info.frame_format)
-               pix->field = V4L2_FIELD_INTERLACED;
-       else
-               pix->field = V4L2_FIELD_NONE;
-
-       ret = __vpfe_get_format(vpfe, &vpfe->v_fmt, &vpfe->bpp);
+       ret = __subdev_get_format(vpfe, &mbus_fmt);
        if (ret)
                return ret;
 
-       fmt = find_format_by_pix(vpfe, pix->pixelformat);
+       fmt = find_format_by_code(vpfe, mbus_fmt.code);
        if (!fmt) {
-               vpfe_dbg(3, vpfe, "Invalid pixel code: %4.4s\n",
-                        (char *)&pix->pixelformat);
+               vpfe_dbg(3, vpfe, "mbus code format (0x%08x) not found.\n",
+                        mbus_fmt.code);
                return -EINVAL;
        }
+
+       /* Save current subdev format */
+       v4l2_fill_pix_format(&vpfe->v_fmt.fmt.pix, &mbus_fmt);
+       vpfe->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       vpfe->v_fmt.fmt.pix.pixelformat = fmt->fourcc;
+       vpfe_calc_format_size(vpfe, fmt, &vpfe->v_fmt);
        vpfe->fmt = fmt;
 
        /* Update the crop window based on found values */
-       vpfe->crop.width = pix->width;
-       vpfe->crop.height = pix->height;
+       vpfe->crop.top = 0;
+       vpfe->crop.left = 0;
+       vpfe->crop.width = mbus_fmt.width;
+       vpfe->crop.height = mbus_fmt.height;
 
        return vpfe_config_ccdc_image_format(vpfe);
 }
@@ -1359,83 +1312,74 @@ static int vpfe_querycap(struct file *file, void  *priv,
 }
 
 /* get the format set at output pad of the adjacent subdev */
-static int __vpfe_get_format(struct vpfe_device *vpfe,
-                            struct v4l2_format *format, unsigned int *bpp)
+static int __subdev_get_format(struct vpfe_device *vpfe,
+                              struct v4l2_mbus_framefmt *fmt)
 {
-       struct v4l2_mbus_framefmt mbus_fmt;
-       struct vpfe_subdev_info *sdinfo;
-       struct v4l2_subdev_format fmt;
+       struct v4l2_subdev *sd = vpfe->current_subdev->sd;
+       struct v4l2_subdev_format sd_fmt;
+       struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
        int ret;
 
-       sdinfo = vpfe->current_subdev;
-       if (!sdinfo->sd)
-               return -EINVAL;
+       sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+       sd_fmt.pad = 0;
 
-       fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-       fmt.pad = 0;
-
-       ret = v4l2_subdev_call(sdinfo->sd, pad, get_fmt, NULL, &fmt);
-       if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV)
+       ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt);
+       if (ret)
                return ret;
 
-       if (!ret) {
-               v4l2_fill_pix_format(&format->fmt.pix, &fmt.format);
-               mbus_to_pix(vpfe, &fmt.format, &format->fmt.pix, bpp);
-       } else {
-               ret = v4l2_device_call_until_err(&vpfe->v4l2_dev,
-                                                sdinfo->grp_id,
-                                                pad, get_fmt,
-                                                NULL, &fmt);
-               if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV)
-                       return ret;
-               v4l2_fill_pix_format(&format->fmt.pix, &mbus_fmt);
-               mbus_to_pix(vpfe, &mbus_fmt, &format->fmt.pix, bpp);
-       }
+       *fmt = *mbus_fmt;
 
-       format->type = vpfe->v_fmt.type;
-
-       vpfe_dbg(1, vpfe,
-                "%s: size %dx%d (%4.4s) bytesperline = %d, size = %d, bpp = 
%d\n",
-                __func__, format->fmt.pix.width, format->fmt.pix.height,
-                (char *)&format->fmt.pix.pixelformat,
-                format->fmt.pix.bytesperline, format->fmt.pix.sizeimage, *bpp);
+       vpfe_dbg(1, vpfe, "%s: %dx%d code:%04X\n", __func__,
+                fmt->width, fmt->height, fmt->code);
 
        return 0;
 }
 
 /* set the format at output pad of the adjacent subdev */
-static int __vpfe_set_format(struct vpfe_device *vpfe,
-                            struct v4l2_format *format, unsigned int *bpp)
+static int __subdev_set_format(struct vpfe_device *vpfe,
+                              struct v4l2_mbus_framefmt *fmt)
 {
-       struct vpfe_subdev_info *sdinfo;
-       struct v4l2_subdev_format fmt;
+       struct v4l2_subdev *sd = vpfe->current_subdev->sd;
+       struct v4l2_subdev_format sd_fmt;
+       struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
        int ret;
 
-       vpfe_dbg(2, vpfe, "%s:\n", __func__);
+       sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+       sd_fmt.pad = 0;
+       *mbus_fmt = *fmt;
 
-       sdinfo = vpfe->current_subdev;
-       if (!sdinfo->sd)
-               return -EINVAL;
+       ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &sd_fmt);
+       if (ret)
+               return ret;
 
-       fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-       fmt.pad = 0;
+       vpfe_dbg(1, vpfe, "%s %dx%d code:%04X\n", __func__,
+                fmt->width, fmt->height, fmt->code);
 
-       pix_to_mbus(vpfe, &format->fmt.pix, &fmt.format);
+       return 0;
+}
 
-       ret = v4l2_subdev_call(sdinfo->sd, pad, set_fmt, NULL, &fmt);
-       if (ret)
-               return ret;
+static int vpfe_calc_format_size(struct vpfe_device *vpfe,
+                                const struct vpfe_fmt *fmt,
+                                struct v4l2_format *f)
+{
+       u32 bpp;
 
-       v4l2_fill_pix_format(&format->fmt.pix, &fmt.format);
-       mbus_to_pix(vpfe, &fmt.format, &format->fmt.pix, bpp);
+       if (!fmt) {
+               vpfe_dbg(3, vpfe, "No vpfe_fmt provided!\n");
+               return -EINVAL;
+       }
 
-       format->type = vpfe->v_fmt.type;
+       bpp = __get_bytesperpixel(vpfe, fmt);
 
-       vpfe_dbg(1, vpfe,
-                "%s: size %dx%d (%4.4s) bytesperline = %d, size = %d, bpp = 
%d\n",
-                __func__,  format->fmt.pix.width, format->fmt.pix.height,
-                (char *)&format->fmt.pix.pixelformat,
-                format->fmt.pix.bytesperline, format->fmt.pix.sizeimage, *bpp);
+       /* pitch should be 32 bytes aligned */
+       f->fmt.pix.bytesperline = ALIGN(f->fmt.pix.width * bpp, 32);
+       f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
+                              f->fmt.pix.height;
+
+       vpfe_dbg(3, vpfe, "%s: fourcc: %4.4s size: %dx%d bpl:%d img_size:%d\n",
+                __func__, (char *)&f->fmt.pix.pixelformat,
+                f->fmt.pix.width, f->fmt.pix.height,
+                f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
 
        return 0;
 }
@@ -1479,14 +1423,62 @@ static int vpfe_enum_fmt(struct file *file, void  *priv,
 }
 
 static int vpfe_try_fmt(struct file *file, void *priv,
-                       struct v4l2_format *fmt)
+                       struct v4l2_format *f)
 {
        struct vpfe_device *vpfe = video_drvdata(file);
-       unsigned int bpp;
+       struct v4l2_subdev *sd = vpfe->current_subdev->sd;
+       const struct vpfe_fmt *fmt;
+       struct v4l2_subdev_frame_size_enum fse;
+       int ret, found;
 
-       vpfe_dbg(2, vpfe, "%s:\n", __func__);
+       fmt = find_format_by_pix(vpfe, f->fmt.pix.pixelformat);
+       if (!fmt) {
+               /* default to first entry */
+               vpfe_dbg(3, vpfe, "Invalid pixel code: %x, default used 
instead\n",
+                        f->fmt.pix.pixelformat);
+               fmt = vpfe->active_fmt[0];
+               f->fmt.pix.pixelformat = fmt->fourcc;
+       }
+
+       f->fmt.pix.field = vpfe->v_fmt.fmt.pix.field;
+
+       /* check for/find a valid width/height */
+       ret = 0;
+       found = false;
+       fse.pad = 0;
+       fse.code = fmt->code;
+       fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+       for (fse.index = 0; ; fse.index++) {
+               ret = v4l2_subdev_call(sd, pad, enum_frame_size,
+                                      NULL, &fse);
+               if (ret)
+                       break;
+
+               if (f->fmt.pix.width == fse.max_width &&
+                   f->fmt.pix.height == fse.max_height) {
+                       found = true;
+                       break;
+               } else if (f->fmt.pix.width >= fse.min_width &&
+                          f->fmt.pix.width <= fse.max_width &&
+                          f->fmt.pix.height >= fse.min_height &&
+                          f->fmt.pix.height <= fse.max_height) {
+                       found = true;
+                       break;
+               }
+       }
+
+       if (!found) {
+               /* use existing values as default */
+               f->fmt.pix.width = vpfe->v_fmt.fmt.pix.width;
+               f->fmt.pix.height =  vpfe->v_fmt.fmt.pix.height;
+       }
 
-       return __vpfe_get_format(vpfe, fmt, &bpp);
+       /*
+        * Use current colorspace for now, it will get
+        * updated properly during s_fmt
+        */
+       f->fmt.pix.colorspace = vpfe->v_fmt.fmt.pix.colorspace;
+       return vpfe_calc_format_size(vpfe, fmt, f);
 }
 
 static int vpfe_s_fmt(struct file *file, void *priv,
@@ -1494,43 +1486,40 @@ static int vpfe_s_fmt(struct file *file, void *priv,
 {
        struct vpfe_device *vpfe = video_drvdata(file);
        const struct vpfe_fmt *fmt;
-       struct v4l2_format format;
-       unsigned int bpp;
+       struct v4l2_mbus_framefmt mbus_fmt;
        int ret;
 
-       vpfe_dbg(2, vpfe, "%s:\n", __func__);
-
        /* If streaming is started, return error */
        if (vb2_is_busy(&vpfe->buffer_queue)) {
                vpfe_err(vpfe, "%s device busy\n", __func__);
                return -EBUSY;
        }
 
-       ret = __vpfe_get_format(vpfe, &format, &bpp);
-       if (ret)
+       ret = vpfe_try_fmt(file, priv, f);
+       if (ret < 0)
                return ret;
 
-       if (!cmp_v4l2_format(f, &format)) {
-               /* Sensor format is different from the requested format
-                * so we need to change it
-                */
-               ret = __vpfe_set_format(vpfe, f, &bpp);
-               if (ret)
-                       return ret;
-       } else /* Just make sure all of the fields are consistent */
-               *f = format;
-
        fmt = find_format_by_pix(vpfe, f->fmt.pix.pixelformat);
-       if (!fmt) {
-               vpfe_dbg(3, vpfe, "Invalid pixel code: %4.4s, This should not 
happen!!\n",
-                        (char *)&f->fmt.pix.pixelformat);
+
+       v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, fmt->code);
+
+       ret = __subdev_set_format(vpfe, &mbus_fmt);
+       if (ret)
+               return ret;
+
+       /* Just double check nothing has gone wrong */
+       if (mbus_fmt.code != fmt->code) {
+               vpfe_dbg(3, vpfe,
+                        "%s subdev changed format on us, this should not 
happen\n",
+                        __func__);
                return -EINVAL;
        }
 
-       /* First detach any IRQ if currently attached */
-       vpfe_detach_irq(vpfe);
-       vpfe->v_fmt = *f;
-       vpfe->bpp = bpp;
+       v4l2_fill_pix_format(&vpfe->v_fmt.fmt.pix, &mbus_fmt);
+       vpfe->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       vpfe->v_fmt.fmt.pix.pixelformat  = fmt->fourcc;
+       vpfe_calc_format_size(vpfe, fmt, &vpfe->v_fmt);
+       *f = vpfe->v_fmt;
        vpfe->fmt = fmt;
 
        /* Update the crop window based on found values */
@@ -1546,9 +1535,7 @@ static int vpfe_enum_size(struct file *file, void  *priv,
 {
        struct vpfe_device *vpfe = video_drvdata(file);
        struct v4l2_subdev_frame_size_enum fse;
-       struct vpfe_subdev_info *sdinfo;
-       struct v4l2_mbus_framefmt mbus;
-       struct v4l2_pix_format pix;
+       struct v4l2_subdev *sd = vpfe->current_subdev->sd;
        const struct vpfe_fmt *fmt;
        int ret;
 
@@ -1557,34 +1544,21 @@ static int vpfe_enum_size(struct file *file, void  
*priv,
        /* check for valid format */
        fmt = find_format_by_pix(vpfe, fsize->pixel_format);
        if (!fmt) {
-               vpfe_dbg(3, vpfe, "Invalid pixel code: %x, default used 
instead\n",
-                       fsize->pixel_format);
+               vpfe_dbg(3, vpfe, "Invalid pixel code: %x\n",
+                        fsize->pixel_format);
                return -EINVAL;
        }
 
        memset(fsize->reserved, 0x0, sizeof(fsize->reserved));
 
-       sdinfo = vpfe->current_subdev;
-       if (!sdinfo->sd)
-               return -EINVAL;
-
-       memset(&pix, 0x0, sizeof(pix));
-       /* Construct pix from parameter and use default for the rest */
-       pix.pixelformat = fsize->pixel_format;
-       pix.width = 640;
-       pix.height = 480;
-       pix.colorspace = V4L2_COLORSPACE_SRGB;
-       pix.field = V4L2_FIELD_NONE;
-       pix_to_mbus(vpfe, &pix, &mbus);
-
        memset(&fse, 0x0, sizeof(fse));
        fse.index = fsize->index;
        fse.pad = 0;
-       fse.code = mbus.code;
+       fse.code = fmt->code;
        fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-       ret = v4l2_subdev_call(sdinfo->sd, pad, enum_frame_size, NULL, &fse);
+       ret = v4l2_subdev_call(sd, pad, enum_frame_size, NULL, &fse);
        if (ret)
-               return -EINVAL;
+               return ret;
 
        vpfe_dbg(1, vpfe, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n",
                __func__, fse.index, fse.code, fse.min_width, fse.max_width,
@@ -2091,6 +2065,7 @@ vpfe_s_selection(struct file *file, void *fh, struct 
v4l2_selection *s)
        struct vpfe_device *vpfe = video_drvdata(file);
        struct v4l2_rect cr = vpfe->crop;
        struct v4l2_rect r = s->r;
+       u32 bpp;
 
        /* If streaming is started, return error */
        if (vb2_is_busy(&vpfe->buffer_queue)) {
@@ -2116,7 +2091,8 @@ vpfe_s_selection(struct file *file, void *fh, struct 
v4l2_selection *s)
 
        s->r = vpfe->crop = r;
 
-       vpfe_ccdc_set_image_window(&vpfe->ccdc, &r, vpfe->bpp);
+       bpp = __get_bytesperpixel(vpfe, vpfe->fmt);
+       vpfe_ccdc_set_image_window(&vpfe->ccdc, &r, bpp);
        vpfe->v_fmt.fmt.pix.width = r.width;
        vpfe->v_fmt.fmt.pix.height = r.height;
        vpfe->v_fmt.fmt.pix.bytesperline =
diff --git a/drivers/media/platform/am437x/am437x-vpfe.h 
b/drivers/media/platform/am437x/am437x-vpfe.h
index 64a25bf720e4..0d10d2b4d7a2 100644
--- a/drivers/media/platform/am437x/am437x-vpfe.h
+++ b/drivers/media/platform/am437x/am437x-vpfe.h
@@ -282,8 +282,6 @@ struct vpfe_device {
        /* Used to store pixel format */
        const struct vpfe_fmt *fmt;
        struct v4l2_format v_fmt;
-       /* Used to store current bytes per pixel based on current format */
-       unsigned int bpp;
        struct vpfe_fmt *active_fmt[VPFE_MAX_ACTIVE_FMT];
        unsigned int num_active_fmt;
 
-- 
2.17.1

Reply via email to