On Sun, 24 Aug 2025 at 10:54, Antheas Kapenekakis <l...@antheas.dev> wrote: > > 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.
Well Phil managed to fall into the value 332800, which has a 0 minor bit. Unfortunate. In hindsight, every 256 hundreds there would be a zero anyway. Before I made this patch I made a partial refactor of panel-quirks where a quirk like this could go to. But I would really prefer not to do quirks. Ill send that too. Antheas > 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 > >