backlight_pwm_to_millipercent_legacy() finds the closest backlight_lut
entry and returns its whole percent. That was the exact inverse while
backlight_millipercent_to_pwm_legacy() only returned LUT entries. Now
that it interpolates, a request of 1.5% programs a PWM halfway between
two entries, which reads back as 1% or 2%, and setting the value read
back moves the backlight by up to half a LUT step

Interpolate between the two entries around the PWM instead. A PWM equal
to a LUT entry still reads back as that entry's whole percent

Signed-off-by: Hugo Sales <[email protected]>
---
Converting a percentage to PWM, back, and to PWM again now moves the
PWM by about a two-thousandth of the LUT step around it, plus rounding.
On the GV301QH LUT, whose steps are at most 1799, that keeps every PWM
within 1 of where it started. A curve with much wider steps can move
further, but by far less than the half step it could before

KUnit: dm_test_pwm_lut_readback from patch 6 fails without this patch
and passes with it
---
 .../gpu/drm/amd/display/modules/power/power_abm.c  | 33 ++++++++--------------
 1 file changed, 11 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/modules/power/power_abm.c 
b/drivers/gpu/drm/amd/display/modules/power/power_abm.c
index d9c1f1401b604..83d79c20281ec 100644
--- a/drivers/gpu/drm/amd/display/modules/power/power_abm.c
+++ b/drivers/gpu/drm/amd/display/modules/power/power_abm.c
@@ -409,34 +409,23 @@ static unsigned int backlight_pwm_to_millipercent_legacy(
                        break;
        }
 
-       /* In this case, exact match is not found. Check if mid/min/max
-        * value is actually closer.
-        */
+       /* No exact match, so on a sorted LUT lut[max] < pwm < lut[min] */
        if (max < min) {
-               unsigned int min_delta;
-               unsigned int mid_delta;
-               unsigned int max_delta;
-
-               min_delta = (core_power->bl_prop[inst].backlight_lut[min] > 
pwm) ?
-                               core_power->bl_prop[inst].backlight_lut[min] - 
pwm :
-                               pwm - 
core_power->bl_prop[inst].backlight_lut[min];
-
-               mid_delta = (core_power->bl_prop[inst].backlight_lut[mid] > 
pwm) ?
-                               core_power->bl_prop[inst].backlight_lut[mid] - 
pwm :
-                               pwm - 
core_power->bl_prop[inst].backlight_lut[mid];
+               unsigned int lower = 
core_power->bl_prop[inst].backlight_lut[max];
+               unsigned int upper = 
core_power->bl_prop[inst].backlight_lut[min];
+               unsigned long long span, den;
 
-               max_delta = (core_power->bl_prop[inst].backlight_lut[max] > 
pwm) ?
-                               core_power->bl_prop[inst].backlight_lut[max] - 
pwm :
-                               pwm - 
core_power->bl_prop[inst].backlight_lut[max];
+               if (pwm <= lower || pwm >= upper)
+                       return BACKLIGHT_MILLIPERCENT_MAX * mid / max_index;
 
-               if ((min_delta < mid_delta) && (min_delta < max_delta))
-                       mid = min;
+               span = upper - lower;
+               den = span * max_index;
 
-               if ((max_delta < mid_delta) && (max_delta < min_delta))
-                       mid = max;
+               /* LUT entries fit in 16 bits, so this stays far below 2^64 */
+               return (unsigned int)div64_u64((max * span + pwm - lower) *
+                                              BACKLIGHT_MILLIPERCENT_MAX + den 
/ 2, den);
        }
 
-       /* No interpolation, just take closest index */
        millipercent = BACKLIGHT_MILLIPERCENT_MAX * mid / max_index;
 
        return millipercent;

-- 
2.56.0

Reply via email to