The custom brightness curve code expects the input signals and luminances of the ATIF curve to increase monotonically. They come from firmware as u8 values, and nothing checks them
Check the curve once, in amdgpu_dm_validate_backlight_caps(), next to the signal range check. If a signal falls, drop the curve and map linearly. Cap a luminance over 100% at 100%, and raise a luminance that falls back to the one before it. When the check changes the curve, warn about a firmware bug The curve code only caps its result at 100%. A point over 100% then makes the curve reach full brightness before that point and stay flat up to it. With the point capped, the curve reaches full brightness at the point itself Dropping the curve also changes ABM. The power module rejected a curve whose signals fall and built its default quadratic LUT. With no points it builds a linear LUT over the firmware's signal range and uses the firmware's AC and DC levels, as it does when firmware reports no curve. The power module still rejects a capped or raised luminance, as before Signed-off-by: Hugo Sales <[email protected]> --- The data_points clamp duplicates "drm/amdgpu: Clamp the ATIF backlight curve to its 99 points", which fixes the overflow where the ATIF reply is read: https://lore.kernel.org/r/[email protected] This check stays correct whichever of the two lands first The check keeps a repeated signal, which the mapping steps over as before. It sits in amdgpu_dm rather than in amdgpu_atif_query_backlight_caps() so KUnit on UML, which has no ACPI, can reach it --- .../amd/display/amdgpu_dm/amdgpu_dm_backlight.c | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c index 358ba0c73d795..3a27fb956627a 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c @@ -52,6 +52,48 @@ #include "dm_helpers.h" #if defined(CONFIG_ACPI) || IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST) +/* + * The brightness mapping needs signals that never fall from point to point + * and luminance that never falls or passes 100%. Drop a curve whose + * signals fall, and flatten the luminance of the others + */ +static void backlight_validate_custom_curve(struct amdgpu_display_manager *dm, + struct amdgpu_dm_backlight_caps *caps) +{ + struct amdgpu_dm_luminance_data *p = caps->luminance_data; + int over = 0, falling = 0; + int i; + + if (caps->data_points > ARRAY_SIZE(caps->luminance_data)) + caps->data_points = ARRAY_SIZE(caps->luminance_data); + + for (i = 1; i < caps->data_points; i++) { + if (p[i].input_signal < p[i - 1].input_signal) { + drm_warn(adev_to_drm(dm->adev), FW_BUG + "ATIF: backlight curve signal %u at point %d is below %u, using a linear curve\n", + p[i].input_signal, i, p[i - 1].input_signal); + caps->data_points = 0; + return; + } + } + + for (i = 0; i < caps->data_points; i++) { + if (p[i].luminance > 100) { + p[i].luminance = 100; + over++; + } + if (i && p[i].luminance < p[i - 1].luminance) { + p[i].luminance = p[i - 1].luminance; + falling++; + } + } + + if (over || falling) + drm_warn(adev_to_drm(dm->adev), FW_BUG + "ATIF: backlight curve has %d points over 100%%, set to 100%%, and %d falling points, raised to the point before\n", + over, falling); +} + STATIC_IFN_KUNIT void amdgpu_dm_validate_backlight_caps(struct amdgpu_display_manager *dm, int bl_idx) { @@ -66,6 +108,8 @@ void amdgpu_dm_validate_backlight_caps(struct amdgpu_display_manager *dm, int bl caps->min_input_signal, caps->max_input_signal); caps->caps_valid = false; } + + backlight_validate_custom_curve(dm, caps); } EXPORT_IF_KUNIT(amdgpu_dm_validate_backlight_caps); #endif -- 2.56.0
