Hi Maxime,

I've taken the whole serie and made some tests on STM32 platform using 
DVP parallel interface.
Now JPEG is OK and I've not seen any regressions appart on framerate 
control linked to this current patchset.

Here are issues observed around framerate control:
1) Framerate enumeration is buggy and all resolutions are claimed 
supporting 15/30/60:
v4l2-ctl --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
         Index       : 0
         Type        : Video Capture
         Pixel Format: 'JPEG' (compressed)
         Name        : JFIF JPEG
                 Size: Discrete 176x144
                         Interval: Discrete 0.067s (15.000 fps)
                         Interval: Discrete 0.033s (30.000 fps)
                         Interval: Discrete 0.017s (60.000 fps)
                 Size: Discrete 320x240
                         Interval: Discrete 0.067s (15.000 fps)
                         Interval: Discrete 0.033s (30.000 fps)
                         Interval: Discrete 0.017s (60.000 fps)
                 Size: Discrete 640x480
                         Interval: Discrete 0.067s (15.000 fps)
                         Interval: Discrete 0.033s (30.000 fps)
                         Interval: Discrete 0.017s (60.000 fps)
                 Size: Discrete 720x480
                         Interval: Discrete 0.067s (15.000 fps)
                         Interval: Discrete 0.033s (30.000 fps)
                         Interval: Discrete 0.017s (60.000 fps)
                 Size: Discrete 720x576
                         Interval: Discrete 0.067s (15.000 fps)
                         Interval: Discrete 0.033s (30.000 fps)
                         Interval: Discrete 0.017s (60.000 fps)
                 Size: Discrete 1024x768
                         Interval: Discrete 0.067s (15.000 fps)
                         Interval: Discrete 0.033s (30.000 fps)
                         Interval: Discrete 0.017s (60.000 fps)
                 Size: Discrete 1280x720
                         Interval: Discrete 0.067s (15.000 fps)
                         Interval: Discrete 0.033s (30.000 fps)
                         Interval: Discrete 0.017s (60.000 fps)
                 Size: Discrete 1920x1080
                         Interval: Discrete 0.067s (15.000 fps)
                         Interval: Discrete 0.033s (30.000 fps)
                         Interval: Discrete 0.017s (60.000 fps)
                 Size: Discrete 2592x1944
                         Interval: Discrete 0.067s (15.000 fps)
                         Interval: Discrete 0.033s (30.000 fps)
                         Interval: Discrete 0.017s (60.000 fps)

2) Frame interval setting is returning incorrect value (*1000):
v4l2-ctl --set-parm=15
<
Frame rate set to 15000.000 fps

3) After having fixed 1) and 2), 720x480 60fps is still supported:
                 Size: Discrete 640x480
                         Interval: Discrete 0.067s (15.000 fps)
                         Interval: Discrete 0.033s (30.000 fps)
                         Interval: Discrete 0.017s (60.000 fps)
                 Size: Discrete 720x480
                         Interval: Discrete 0.067s (15.000 fps)
                         Interval: Discrete 0.033s (30.000 fps)
                         Interval: Discrete 0.017s (60.000 fps)

Some fixes are proposed below:


On 04/16/2018 02:37 PM, Maxime Ripard wrote:
> Now that we have everything in place to compute the clock rate at runtime,
> we can enable the 60fps framerate for the mode we tested it with.
> 
> Signed-off-by: Maxime Ripard <maxime.rip...@bootlin.com>
> ---
>   drivers/media/i2c/ov5640.c | 33 +++++++++++++++++++++++++--------
>   1 file changed, 25 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
> index 690ed0238763..c01bbc5f9f34 100644
> --- a/drivers/media/i2c/ov5640.c
> +++ b/drivers/media/i2c/ov5640.c
> @@ -112,6 +112,7 @@ enum ov5640_mode_id {
>   enum ov5640_frame_rate {
>       OV5640_15_FPS = 0,
>       OV5640_30_FPS,
> +     OV5640_60_FPS,
>       OV5640_NUM_FRAMERATES,
>   };
>   
> @@ -140,6 +141,7 @@ MODULE_PARM_DESC(virtual_channel,
>   static const int ov5640_framerates[] = {
>       [OV5640_15_FPS] = 15,
>       [OV5640_30_FPS] = 30,
> +     [OV5640_60_FPS] = 60,
>   };
>   
>   /* regulator supplies */
> @@ -1398,12 +1400,19 @@ ov5640_find_mode(struct ov5640_dev *sensor, enum 
> ov5640_frame_rate fr,
>                               /* try to find another mode */
>                               continue;
>   
> +                     /* Only 640x480 can operate at 60fps (for now) */
> +                     if (fr == OV5640_60_FPS &&
> +                         width != 640 && height != 480)

Should be
+                           !(width == 640 && height == 480))
otherwise 720x480 is also supported (bug 3))

> +                             /* try to find another mode */
> +                             continue;
> +
>                       break;
>               }
>       }
>   
> +     /* VGA is the only mode that supports all the framerates */
>       if (nearest && i < 0)
> -             mode = &ov5640_mode_data[0];
> +             mode = &ov5640_mode_data[OV5640_MODE_VGA_640_480];

Code is missing to reject unsupported framerates when nearest is not 
set, this fix enumeration bug 1):
-       if (nearest && i < 0)
+       if (i < 0) {
+               /* no match */
+               if (!nearest)
+                       return NULL;
                mode = &ov5640_mode_data[OV5640_MODE_VGA_640_480];
+       }

Anyway I need to rework this code using new Sakari 
v4l2_find_nearest_size() code as stated in:
https://patchwork.linuxtv.org/patch/47767/


>   
>       return mode;
>   }
> @@ -1848,12 +1857,13 @@ static int ov5640_try_frame_interval(struct 
> ov5640_dev *sensor,
>       int ret;
>   
>       minfps = ov5640_framerates[OV5640_15_FPS];
> -     maxfps = ov5640_framerates[OV5640_30_FPS];
> +     maxfps = ov5640_framerates[OV5640_60_FPS];
>   
>       if (fi->numerator == 0) {
>               fi->denominator = maxfps;
>               fi->numerator = 1;
> -             return OV5640_30_FPS;
> +             ret = OV5640_60_FPS;
> +             goto find_mode;
>       }
>   
>       fps = DIV_ROUND_CLOSEST(fi->denominator, fi->numerator);
> @@ -1865,11 +1875,15 @@ static int ov5640_try_frame_interval(struct 
> ov5640_dev *sensor,
>               fi->denominator = minfps;
>       else if (2 * fps >= 2 * minfps + (maxfps - minfps))
>               fi->denominator = maxfps;

else is missing here leading to denominator untouched while numerator 
has been reset to 1, leading to bug 2).
In fact, original code is valid for only 2 values, min and max, by 
adding a third fps value, rework of the conditions are needed using a 
"mid" value, see proposed code:

static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
                                     struct v4l2_fract *fi,
                                     u32 width, u32 height)
  {
        const struct ov5640_mode_info *mode;
-       u32 minfps, maxfps, fps;
+       u32 minfps, midfps, maxfps, fps;
        int ret;

        minfps = ov5640_framerates[OV5640_15_FPS];
-       maxfps = ov5640_framerates[OV5640_30_FPS];
+       midfps = ov5640_framerates[OV5640_30_FPS];
+       maxfps = ov5640_framerates[OV5640_60_FPS];

        if (fi->numerator == 0) {
                fi->denominator = maxfps;
                fi->numerator = 1;
-               return OV5640_30_FPS;
+               ret = OV5640_60_FPS;
+               goto find_mode;
        }

        fps = DIV_ROUND_CLOSEST(fi->denominator, fi->numerator);

        fi->numerator = 1;
-       if (fps > maxfps)
+       if ((fps >= maxfps) ||
+           ((2 * fps >= (midfps + maxfps)) && (fps < maxfps)))
                fi->denominator = maxfps;
-       else if (fps < minfps)
+       else if ((fps <= minfps)  ||
+                ((2 * fps <= (minfps + midfps)) && (fps > minfps)))
                fi->denominator = minfps;
-       else if (2 * fps >= 2 * minfps + (maxfps - minfps))
-               fi->denominator = maxfps;
        else
-               fi->denominator = minfps;
+               fi->denominator = midfps;

-       ret = (fi->denominator == minfps) ? OV5640_15_FPS : OV5640_30_FPS;
+       if (fi->denominator == minfps)
+               ret = OV5640_15_FPS;
+       else if (fi->denominator == maxfps)
+               ret = OV5640_60_FPS;
+       else
+               ret = OV5640_30_FPS;

+find_mode:
        mode = ov5640_find_mode(sensor, ret, width, height, false);
        return mode ? ret : -EINVAL;
  }

This code has been tested using v4l2-ctl:

v4l2-ctl --set-fmt-video=width=640,height=480,pixelformat=RGBP
v4l2-ctl --set-parm=14
v4l2-ctl --set-parm=15
v4l2-ctl --set-parm=16
v4l2-ctl --set-parm=22
v4l2-ctl --set-parm=23
v4l2-ctl --set-parm=24
v4l2-ctl --set-parm=29
v4l2-ctl --set-parm=30
v4l2-ctl --set-parm=31
v4l2-ctl --set-parm=36
v4l2-ctl --set-parm=42
v4l2-ctl --set-parm=45
v4l2-ctl --set-parm=46
v4l2-ctl --set-parm=59
v4l2-ctl --set-parm=60
v4l2-ctl --set-parm=61
root@stm32mp1:~# v4l2-ctl --set-parm=14
Frame rate set to 15.000 fps
root@stm32mp1:~# v4l2-ctl --set-parm=15
Frame rate set to 15.000 fps
root@stm32mp1:~# v4l2-ctl --set-parm=16
Frame rate set to 15.000 fps
root@stm32mp1:~# v4l2-ctl --set-parm=22
Frame rate set to 15.000 fps
root@stm32mp1:~# v4l2-ctl --set-parm=23
Frame rate set to 30.000 fps
root@stm32mp1:~# v4l2-ctl --set-parm=24
Frame rate set to 30.000 fps
root@stm32mp1:~# v4l2-ctl --set-parm=29
Frame rate set to 30.000 fps
root@stm32mp1:~# v4l2-ctl --set-parm=30
Frame rate set to 30.000 fps
root@stm32mp1:~# v4l2-ctl --set-parm=31
Frame rate set to 30.000 fps
root@stm32mp1:~# v4l2-ctl --set-parm=36
Frame rate set to 30.000 fps
root@stm32mp1:~# v4l2-ctl --set-parm=42
Frame rate set to 30.000 fps
root@stm32mp1:~# v4l2-ctl --set-parm=45
Frame rate set to 60.000 fps
root@stm32mp1:~# v4l2-ctl --set-parm=46
Frame rate set to 60.000 fps
root@stm32mp1:~# v4l2-ctl --set-parm=59
Frame rate set to 60.000 fps
root@stm32mp1:~# v4l2-ctl --set-parm=60
Frame rate set to 60.000 fps
root@stm32mp1:~# v4l2-ctl --set-parm=61
Frame rate set to 60.000 fps


> @@ -2458,8 +2472,11 @@ static int ov5640_s_frame_interval(struct v4l2_subdev 
> *sd,
>   
>       frame_rate = ov5640_try_frame_interval(sensor, &fi->interval,
>                                              mode->hact, mode->vact);
> -     if (frame_rate < 0)
> -             frame_rate = OV5640_15_FPS;
> +     if (frame_rate < 0) {
> +             /* Always return a valid frame interval value */
> +             fi->interval = sensor->frame_interval;
> +             goto out;
> +     }
>   
>       sensor->current_fr = frame_rate;
>       sensor->frame_interval = fi->interval;
> 


Best regards,
Hugues.

Reply via email to