Certain OLED devices malfunction on specific brightness levels. Specifically, when DP_SOURCE_BACKLIGHT_LEVEL is written to with the minor byte being 0x00 and sometimes 0x01, the panel forcibly turns off until the device sleeps again. This is an issue on multiple handhelds, including OneXPlayer F1 Pro and Ayaneo 3 (the panel is suspected to be the same-1080p 7in OLED).
Below are some examples. This was found by iterating over brighness ranges while printing DP_SOURCE_BACKLIGHT_LEVEL. It was found that the screen would malfunction on specific values, and some of them were collected. Broken: 86016: 10101000000000000 86272: 10101000100000000 87808: 10101011100000000 251648: 111101011100000000 251649: 111101011100000001 Working: 86144: 10101000010000000 87809: 10101011100000001 251650: 111101011100000010 The reason for this is that the range manipulation is too granular. AUX is currently written to with a granularity of 1. Forcing 100, which on the Ayaneo 3 OLED yields 400*10=4000 values, is plenty of granularity and fixes this issue. Iterating over the values through Python shows that the final byte is never 0x00, and testing over the entire range with a cadence of 0.2s/it and 73 increments (to saturate the range) shows no issues. Windows likewise shows no issues. Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3803 Signed-off-by: Antheas Kapenekakis <l...@antheas.dev> --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index cd0e2976e268..bb16adcafb88 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -4739,7 +4739,8 @@ static void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm, } static int get_brightness_range(const struct amdgpu_dm_backlight_caps *caps, - unsigned int *min, unsigned int *max) + unsigned int *min, unsigned int *max, + unsigned int *multiple) { if (!caps) return 0; @@ -4748,10 +4749,12 @@ static int get_brightness_range(const struct amdgpu_dm_backlight_caps *caps, // Firmware limits are in nits, DC API wants millinits. *max = 1000 * caps->aux_max_input_signal; *min = 1000 * caps->aux_min_input_signal; + *multiple = 100; } else { // Firmware limits are 8-bit, PWM control is 16-bit. *max = 0x101 * caps->max_input_signal; *min = 0x101 * caps->min_input_signal; + *multiple = 1; } return 1; } @@ -4813,23 +4816,25 @@ static void convert_custom_brightness(const struct amdgpu_dm_backlight_caps *cap static u32 convert_brightness_from_user(const struct amdgpu_dm_backlight_caps *caps, uint32_t brightness) { - unsigned int min, max; + unsigned int min, max, multiple; - if (!get_brightness_range(caps, &min, &max)) + if (!get_brightness_range(caps, &min, &max, &multiple)) return brightness; convert_custom_brightness(caps, min, max, &brightness); - // Rescale 0..max to min..max - return min + DIV_ROUND_CLOSEST_ULL((u64)(max - min) * brightness, max); + // Rescale 0..max to min..max rounding to nearest multiple + return rounddown( + min + DIV_ROUND_CLOSEST_ULL((u64)(max - min) * brightness, max), + multiple); } static u32 convert_brightness_to_user(const struct amdgpu_dm_backlight_caps *caps, uint32_t brightness) { - unsigned int min, max; + unsigned int min, max, multiple; - if (!get_brightness_range(caps, &min, &max)) + if (!get_brightness_range(caps, &min, &max, &multiple)) return brightness; if (brightness < min) @@ -4970,7 +4975,7 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) struct backlight_properties props = { 0 }; struct amdgpu_dm_backlight_caps *caps; char bl_name[16]; - int min, max; + int min, max, multiple; if (aconnector->bl_idx == -1) return; @@ -4983,15 +4988,16 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) } caps = &dm->backlight_caps[aconnector->bl_idx]; - if (get_brightness_range(caps, &min, &max)) { + if (get_brightness_range(caps, &min, &max, &multiple)) { if (power_supply_is_system_supplied() > 0) props.brightness = DIV_ROUND_CLOSEST((max - min) * caps->ac_level, 100); else props.brightness = DIV_ROUND_CLOSEST((max - min) * caps->dc_level, 100); /* min is zero, so max needs to be adjusted */ props.max_brightness = max - min; - drm_dbg(drm, "Backlight caps: min: %d, max: %d, ac %d, dc %d\n", min, max, - caps->ac_level, caps->dc_level); + drm_dbg(drm, + "Backlight caps: min: %d, max: %d, ac %d, dc %d, multiple: %d\n", + min, max, caps->ac_level, caps->dc_level, multiple); } else props.brightness = props.max_brightness = MAX_BACKLIGHT_LEVEL; -- 2.50.1