Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm: panel-backlight-quirks: Add brightness mask quirk

Certain OLED devices malfunction on specific brightness levels.
Specifically, when DP_SOURCE_BACKLIGHT_LEVEL is written to with
the first byte being 0x00 and sometimes 0x01, the panel forcibly
turns off until the device sleeps again.

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.

Therefore, introduce a quirk where the minor byte of brightness is
OR'd with 0x03 to avoid the range of invalid values.

This quirk was tested by removing the workarounds and iterating
from 0 to 50_000 value ranges with a cadence of 0.2s/it. The
range of the panel is 1000...400_000, so the values were slightly
interpolated during testing. The custom brightness curve added on
6.15 was disabled.

86016: 10101000000000000
86272: 10101000100000000
87808: 10101011100000000
251648: 111101011100000000
251649: 111101011100000001

86144: 10101000010000000
87809: 10101011100000001
251650: 111101011100000010

Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3803
Tested-by: Philip Müller <philm@manjaro.org>
Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
Link: https://lore.kernel.org/r/20250829145541.512671-5-lkml@antheas.dev
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Mario Limonciello (AMD) <superm1@kernel.org>

authored by

Antheas Kapenekakis and committed by
Mario Limonciello (AMD)
aef10b11 f7033fab

+49
+7
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
··· 3662 3662 if (panel_backlight_quirk->min_brightness) 3663 3663 caps->min_input_signal = 3664 3664 panel_backlight_quirk->min_brightness - 1; 3665 + if (panel_backlight_quirk->brightness_mask) 3666 + caps->brightness_mask = 3667 + panel_backlight_quirk->brightness_mask; 3665 3668 } 3666 3669 } 3667 3670 ··· 4864 4861 amdgpu_atombios_scratch_regs_set_backlight_level(dm->adev, dm->brightness[bl_idx]); 4865 4862 brightness = convert_brightness_from_user(caps, dm->brightness[bl_idx]); 4866 4863 link = (struct dc_link *)dm->backlight_link[bl_idx]; 4864 + 4865 + /* Apply brightness quirk */ 4866 + if (caps->brightness_mask) 4867 + brightness |= caps->brightness_mask; 4867 4868 4868 4869 /* Change brightness based on AUX property */ 4869 4870 mutex_lock(&dm->dc_lock);
+5
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
··· 201 201 */ 202 202 bool aux_support; 203 203 /** 204 + * @brightness_mask: After deriving brightness, OR it with this mask. 205 + * Workaround for panels with issues with certain brightness values. 206 + */ 207 + u32 brightness_mask; 208 + /** 204 209 * @ac_level: the default brightness if booted on AC 205 210 */ 206 211 u8 ac_level;
+36
drivers/gpu/drm/drm_panel_backlight_quirks.c
··· 45 45 .ident.name = "NE135A1M-NY1", 46 46 .quirk = { .min_brightness = 1, }, 47 47 }, 48 + /* Have OLED Panels with brightness issue when last byte is 0/1 */ 49 + { 50 + .dmi_match.field = DMI_SYS_VENDOR, 51 + .dmi_match.value = "AYANEO", 52 + .dmi_match_other.field = DMI_PRODUCT_NAME, 53 + .dmi_match_other.value = "AYANEO 3", 54 + .quirk = { .brightness_mask = 3, }, 55 + }, 56 + { 57 + .dmi_match.field = DMI_SYS_VENDOR, 58 + .dmi_match.value = "ZOTAC", 59 + .dmi_match_other.field = DMI_BOARD_NAME, 60 + .dmi_match_other.value = "G0A1W", 61 + .quirk = { .brightness_mask = 3, }, 62 + }, 63 + { 64 + .dmi_match.field = DMI_SYS_VENDOR, 65 + .dmi_match.value = "ZOTAC", 66 + .dmi_match_other.field = DMI_BOARD_NAME, 67 + .dmi_match_other.value = "G1A1W", 68 + .quirk = { .brightness_mask = 3, }, 69 + }, 70 + { 71 + .dmi_match.field = DMI_SYS_VENDOR, 72 + .dmi_match.value = "ONE-NETBOOK", 73 + .dmi_match_other.field = DMI_PRODUCT_NAME, 74 + .dmi_match_other.value = "ONEXPLAYER F1Pro", 75 + .quirk = { .brightness_mask = 3, }, 76 + }, 77 + { 78 + .dmi_match.field = DMI_SYS_VENDOR, 79 + .dmi_match.value = "ONE-NETBOOK", 80 + .dmi_match_other.field = DMI_PRODUCT_NAME, 81 + .dmi_match_other.value = "ONEXPLAYER F1 EVA-02", 82 + .quirk = { .brightness_mask = 3, }, 83 + }, 48 84 }; 49 85 50 86 static bool drm_panel_min_backlight_quirk_matches(
+1
include/drm/drm_utils.h
··· 18 18 19 19 struct drm_panel_backlight_quirk { 20 20 u16 min_brightness; 21 + u32 brightness_mask; 21 22 }; 22 23 23 24 const struct drm_panel_backlight_quirk *