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
