On Mon, Jul 20, 2020 at 09:25:20PM -0700, Alexandru Stan wrote:
> Whenever num-interpolated-steps was larger than the distance
> between 2 consecutive brightness levels the table would get really
> discontinuous. The slope of the interpolation would stick with
> integers only and if it was 0 the whole line segment would get skipped.
> 
> Example settings:
>       brightness-levels = <0 1 2 4 8 16 32 64 128 256>;
>       num-interpolated-steps = <16>;
> 
> The distances between 1 2 4 and 8 would be 1, and only starting with 16
> it would start to interpolate properly.
> 
> Let's change it so there's always interpolation happening, even if
> there's no enough points available (read: values in the table would
> appear more than once). This should match the expected behavior much
> more closely.
> 
> Reviewed-by: Douglas Anderson <diand...@chromium.org>
> Reviewed-by: Matthias Kaehlcke <m...@chromium.org>
> Signed-off-by: Alexandru Stan <ams...@chromium.org>

Apologies for the delay. Patch 2/3 meant I had some thinking to do...
and then the holiday's took their toll.

Overall this looks good, just some quibbles about broken 64-bit maths.


> ---
> 
>  drivers/video/backlight/pwm_bl.c | 70 ++++++++++++++------------------
>  1 file changed, 31 insertions(+), 39 deletions(-)
> 
> diff --git a/drivers/video/backlight/pwm_bl.c 
> b/drivers/video/backlight/pwm_bl.c
> index 82b8d7594701..5193a72305a2 100644
> --- a/drivers/video/backlight/pwm_bl.c
> +++ b/drivers/video/backlight/pwm_bl.c
> @@ -235,8 +235,7 @@ static int pwm_backlight_parse_dt(struct device *dev,
>                                 struct platform_pwm_backlight_data *data)
>  {
>       struct device_node *node = dev->of_node;
> -     unsigned int num_levels = 0;
> -     unsigned int levels_count;
> +     unsigned int num_levels;
>       unsigned int num_steps = 0;
>       struct property *prop;
>       unsigned int *table;
> @@ -265,12 +264,11 @@ static int pwm_backlight_parse_dt(struct device *dev,
>       if (!prop)
>               return 0;
>  
> -     data->max_brightness = length / sizeof(u32);
> +     num_levels = length / sizeof(u32);
>  
>       /* read brightness levels from DT property */
> -     if (data->max_brightness > 0) {
> -             size_t size = sizeof(*data->levels) * data->max_brightness;
> -             unsigned int i, j, n = 0;
> +     if (num_levels > 0) {
> +             size_t size = sizeof(*data->levels) * num_levels;
>  
>               data->levels = devm_kzalloc(dev, size, GFP_KERNEL);
>               if (!data->levels)
> @@ -278,7 +276,7 @@ static int pwm_backlight_parse_dt(struct device *dev,
>  
>               ret = of_property_read_u32_array(node, "brightness-levels",
>                                                data->levels,
> -                                              data->max_brightness);
> +                                              num_levels);
>               if (ret < 0)
>                       return ret;
>  
> @@ -303,7 +301,13 @@ static int pwm_backlight_parse_dt(struct device *dev,
>                * between two points.
>                */
>               if (num_steps) {
> -                     if (data->max_brightness < 2) {
> +                     unsigned int num_input_levels = num_levels;
> +                     unsigned int i;
> +                     u32 x1, x2, x;
> +                     u32 y1, y2;
> +                     s64 dx, dy;

dx should be 32-bit. It will be truncated to 32-bit when passed to
div_s64() so this type is actively misleading about how the maths
works.


> +
> +                     if (num_input_levels < 2) {
>                               dev_err(dev, "can't interpolate\n");
>                               return -EINVAL;
>                       }
> @@ -313,14 +317,7 @@ static int pwm_backlight_parse_dt(struct device *dev,
>                        * taking in consideration the number of interpolated
>                        * steps between two levels.
>                        */
> -                     for (i = 0; i < data->max_brightness - 1; i++) {
> -                             if ((data->levels[i + 1] - data->levels[i]) /
> -                                num_steps)
> -                                     num_levels += num_steps;
> -                             else
> -                                     num_levels++;
> -                     }
> -                     num_levels++;
> +                     num_levels = (num_input_levels - 1) * num_steps + 1;
>                       dev_dbg(dev, "new number of brightness levels: %d\n",
>                               num_levels);
>  
> @@ -332,24 +329,25 @@ static int pwm_backlight_parse_dt(struct device *dev,
>                       table = devm_kzalloc(dev, size, GFP_KERNEL);
>                       if (!table)
>                               return -ENOMEM;
> -
> -                     /* Fill the interpolated table. */
> -                     levels_count = 0;
> -                     for (i = 0; i < data->max_brightness - 1; i++) {
> -                             value = data->levels[i];
> -                             n = (data->levels[i + 1] - value) / num_steps;
> -                             if (n > 0) {
> -                                     for (j = 0; j < num_steps; j++) {
> -                                             table[levels_count] = value;
> -                                             value += n;
> -                                             levels_count++;
> -                                     }
> -                             } else {
> -                                     table[levels_count] = data->levels[i];
> -                                     levels_count++;
> +                     /*
> +                      * Fill the interpolated table[x] = y
> +                      * by draw lines between each (x1, y1) to (x2, y2).
> +                      */
> +                     dx = num_steps;
> +                     for (i = 0; i < num_input_levels - 1; i++) {
> +                             x1 = i * dx;
> +                             x2 = x1 + dx;
> +                             y1 = data->levels[i];
> +                             y2 = data->levels[i + 1];
> +                             dy = y2 - y1;

This is an u32 expression being assigned to a s64. I could be rusty on
my fixed point maths but won't this promote too late for the 64-bitness
of dy to be useful?


Daniel.

> +
> +                             for (x = x1; x < x2; x++) {
> +                                     table[x] = y1 +
> +                                             div_s64(dy * (x - x1), dx);
>                               }
>                       }
> -                     table[levels_count] = data->levels[i];
> +                     /* Fill in the last point, since no line starts here. */
> +                     table[x2] = y2;
>  
>                       /*
>                        * As we use interpolation lets remove current
> @@ -358,15 +356,9 @@ static int pwm_backlight_parse_dt(struct device *dev,
>                        */
>                       devm_kfree(dev, data->levels);
>                       data->levels = table;
> -
> -                     /*
> -                      * Reassign max_brightness value to the new total number
> -                      * of brightness levels.
> -                      */
> -                     data->max_brightness = num_levels;
>               }
>  
> -             data->max_brightness--;
> +             data->max_brightness = num_levels - 1;
>       }
>  
>       return 0;
> -- 
> 2.27.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to