* [PATCH v1 0/5] drm: panel-backlight-quirks: Do partial refactor and apply OLED fix
@ 2025-08-24 20:01 Antheas Kapenekakis
2025-08-24 20:01 ` [PATCH v1 1/5] drm: panel-backlight-quirks: Make ident optional Antheas Kapenekakis
` (5 more replies)
0 siblings, 6 replies; 20+ messages in thread
From: Antheas Kapenekakis @ 2025-08-24 20:01 UTC (permalink / raw)
To: amd-gfx
Cc: dri-devel, linux-kernel, philm, Alex Deucher,
Christian König, Mario Limonciello, Antheas Kapenekakis
This is an alternative to [1], since Phil found out there are still invalid
values. I made this series before the one I sent today, and I have to say
I tested it much less. Because I did not think it was very viable to
upstream. I was also not aware of [2] and [3] since they are not in a
public bug tracker such as amddrm and my issue there [4] remains closed.
I lower the cc'd here since this is a draft. But this could have some
viability. Especially since I can stop carrying the dodgy patches from
SteamOS so that the SD OLED has a 0 brightness min.
[1] https://lore.kernel.org/all/20250824085351.454619-2-lkml@antheas.dev/
[2] https://gitlab.manjaro.org/packages/core/linux616/-/blob/master/0001-drm-amd-display-Add-a-quirk-for-the-Zotac-Zone.patch
[3] https://gitlab.manjaro.org/packages/core/linux616/-/blob/master/0004-TEMPORARY-terrible-hack-for-zotac-screen-while-debug.patch
[4] https://gitlab.freedesktop.org/drm/amd/-/issues/3803
Antheas Kapenekakis (5):
drm: panel-backlight-quirks: Make ident optional
drm: panel-backlight-quirks: Convert brightness quirk to generic
structure
drm: panel-backlight-quirks: Add secondary DMI match
drm: panel-backlight-quirks: Add brightness mask quirk
drm: panel-backlight-quirks: Add Steam Decks
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 19 +++-
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 6 +
.../link/protocols/link_edp_panel_control.c | 2 +-
drivers/gpu/drm/drm_panel_backlight_quirks.c | 106 +++++++++++++-----
include/drm/drm_utils.h | 8 +-
5 files changed, 109 insertions(+), 32 deletions(-)
base-commit: c17b750b3ad9f45f2b6f7e6f7f4679844244f0b9
--
2.50.1
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v1 1/5] drm: panel-backlight-quirks: Make ident optional
2025-08-24 20:01 [PATCH v1 0/5] drm: panel-backlight-quirks: Do partial refactor and apply OLED fix Antheas Kapenekakis
@ 2025-08-24 20:01 ` Antheas Kapenekakis
2025-08-24 20:01 ` [PATCH v1 2/5] drm: panel-backlight-quirks: Convert brightness quirk to generic structure Antheas Kapenekakis
` (4 subsequent siblings)
5 siblings, 0 replies; 20+ messages in thread
From: Antheas Kapenekakis @ 2025-08-24 20:01 UTC (permalink / raw)
To: amd-gfx
Cc: dri-devel, linux-kernel, philm, Alex Deucher,
Christian König, Mario Limonciello, Antheas Kapenekakis
Currently, having a valid panel_id match is required to use the quirk
system. For certain devices, we know that all SKUs need a certain quirk.
Therefore, allow not specifying ident by only checking for a match
if panel_id is non-zero.
Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
---
drivers/gpu/drm/drm_panel_backlight_quirks.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c
index 598f812b7cb3..b38b33e26ea5 100644
--- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
+++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
@@ -50,7 +50,7 @@ static bool drm_panel_min_backlight_quirk_matches(const struct drm_panel_min_bac
if (!dmi_match(quirk->dmi_match.field, quirk->dmi_match.value))
return false;
- if (!drm_edid_match(edid, &quirk->ident))
+ if (quirk->ident.panel_id && !drm_edid_match(edid, &quirk->ident))
return false;
return true;
--
2.50.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v1 2/5] drm: panel-backlight-quirks: Convert brightness quirk to generic structure
2025-08-24 20:01 [PATCH v1 0/5] drm: panel-backlight-quirks: Do partial refactor and apply OLED fix Antheas Kapenekakis
2025-08-24 20:01 ` [PATCH v1 1/5] drm: panel-backlight-quirks: Make ident optional Antheas Kapenekakis
@ 2025-08-24 20:01 ` Antheas Kapenekakis
2025-08-25 17:53 ` Mario Limonciello
2025-08-26 12:29 ` Philip Müller
2025-08-24 20:02 ` [PATCH v1 3/5] drm: panel-backlight-quirks: Add secondary DMI match Antheas Kapenekakis
` (3 subsequent siblings)
5 siblings, 2 replies; 20+ messages in thread
From: Antheas Kapenekakis @ 2025-08-24 20:01 UTC (permalink / raw)
To: amd-gfx
Cc: dri-devel, linux-kernel, philm, Alex Deucher,
Christian König, Mario Limonciello, Antheas Kapenekakis
Currently, the brightness quirk is limited to minimum brightness only.
Refactor it to a structure, so that more quirks can be added in the
future. Reserve 0 value for "no quirk", and use u16 to allow minimum
brightness up to 255.
Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 12 ++++--
.../link/protocols/link_edp_panel_control.c | 2 +-
drivers/gpu/drm/drm_panel_backlight_quirks.c | 41 ++++++++++---------
include/drm/drm_utils.h | 7 +++-
4 files changed, 36 insertions(+), 26 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..4ad80ae615a2 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3612,11 +3612,11 @@ static struct drm_mode_config_helper_funcs amdgpu_dm_mode_config_helperfuncs = {
static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
{
+ const struct drm_panel_backlight_quirk *panel_backlight_quirk;
struct amdgpu_dm_backlight_caps *caps;
struct drm_connector *conn_base;
struct amdgpu_device *adev;
struct drm_luminance_range_info *luminance_range;
- int min_input_signal_override;
if (aconnector->bl_idx == -1 ||
aconnector->dc_link->connector_signal != SIGNAL_TYPE_EDP)
@@ -3656,9 +3656,13 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
else
caps->aux_min_input_signal = 1;
- min_input_signal_override = drm_get_panel_min_brightness_quirk(aconnector->drm_edid);
- if (min_input_signal_override >= 0)
- caps->min_input_signal = min_input_signal_override;
+ panel_backlight_quirk =
+ drm_get_panel_backlight_quirk(aconnector->drm_edid);
+ if (!IS_ERR_OR_NULL(panel_backlight_quirk)) {
+ if (panel_backlight_quirk->min_brightness)
+ caps->min_input_signal =
+ panel_backlight_quirk->min_brightness - 1;
+ }
}
DEFINE_FREE(sink_release, struct dc_sink *, if (_T) dc_sink_release(_T))
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
index e7927b8f5ba3..a1f37267b85e 100644
--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
@@ -201,7 +201,7 @@ bool edp_set_backlight_level_nits(struct dc_link *link,
return false;
} else if (link->backlight_control_type == BACKLIGHT_CONTROL_AMD_AUX) {
struct dpcd_source_backlight_set dpcd_backlight_set;
- *(uint32_t *)&dpcd_backlight_set.backlight_level_millinits = backlight_millinits;
+ *(uint32_t *)&dpcd_backlight_set.backlight_level_millinits = backlight_millinits | 3;
*(uint16_t *)&dpcd_backlight_set.backlight_transition_time_ms = (uint16_t)transition_time_in_ms;
uint8_t backlight_control = isHDR ? 1 : 0;
diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c
index b38b33e26ea5..702726c20ccc 100644
--- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
+++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
@@ -8,23 +8,23 @@
#include <drm/drm_edid.h>
#include <drm/drm_utils.h>
-struct drm_panel_min_backlight_quirk {
+struct drm_get_panel_backlight_quirk {
struct {
enum dmi_field field;
const char * const value;
} dmi_match;
struct drm_edid_ident ident;
- u8 min_brightness;
+ struct drm_panel_backlight_quirk quirk;
};
-static const struct drm_panel_min_backlight_quirk drm_panel_min_backlight_quirks[] = {
+static const struct drm_get_panel_backlight_quirk drm_panel_min_backlight_quirks[] = {
/* 13 inch matte panel */
{
.dmi_match.field = DMI_BOARD_VENDOR,
.dmi_match.value = "Framework",
.ident.panel_id = drm_edid_encode_panel_id('B', 'O', 'E', 0x0bca),
.ident.name = "NE135FBM-N41",
- .min_brightness = 0,
+ .quirk = { .min_brightness = 1, },
},
/* 13 inch glossy panel */
{
@@ -32,7 +32,7 @@ static const struct drm_panel_min_backlight_quirk drm_panel_min_backlight_quirks
.dmi_match.value = "Framework",
.ident.panel_id = drm_edid_encode_panel_id('B', 'O', 'E', 0x095f),
.ident.name = "NE135FBM-N41",
- .min_brightness = 0,
+ .quirk = { .min_brightness = 1, },
},
/* 13 inch 2.8k panel */
{
@@ -40,12 +40,13 @@ static const struct drm_panel_min_backlight_quirk drm_panel_min_backlight_quirks
.dmi_match.value = "Framework",
.ident.panel_id = drm_edid_encode_panel_id('B', 'O', 'E', 0x0cb4),
.ident.name = "NE135A1M-NY1",
- .min_brightness = 0,
+ .quirk = { .min_brightness = 1, },
},
};
-static bool drm_panel_min_backlight_quirk_matches(const struct drm_panel_min_backlight_quirk *quirk,
- const struct drm_edid *edid)
+static bool drm_panel_min_backlight_quirk_matches(
+ const struct drm_get_panel_backlight_quirk *quirk,
+ const struct drm_edid *edid)
{
if (!dmi_match(quirk->dmi_match.field, quirk->dmi_match.value))
return false;
@@ -57,39 +58,39 @@ static bool drm_panel_min_backlight_quirk_matches(const struct drm_panel_min_bac
}
/**
- * drm_get_panel_min_brightness_quirk - Get minimum supported brightness level for a panel.
+ * drm_get_panel_backlight_quirk - Get backlight quirks for a panel
* @edid: EDID of the panel to check
*
* This function checks for platform specific (e.g. DMI based) quirks
* providing info on the minimum backlight brightness for systems where this
- * cannot be probed correctly from the hard-/firm-ware.
+ * cannot be probed correctly from the hard-/firm-ware and other sources.
*
* Returns:
- * A negative error value or
- * an override value in the range [0, 255] representing 0-100% to be scaled to
- * the drivers target range.
+ * a drm_panel_backlight_quirk struct if a quirk was found, otherwise an
+ * error pointer.
*/
-int drm_get_panel_min_brightness_quirk(const struct drm_edid *edid)
+const struct drm_panel_backlight_quirk *
+drm_get_panel_backlight_quirk(const struct drm_edid *edid)
{
- const struct drm_panel_min_backlight_quirk *quirk;
+ const struct drm_get_panel_backlight_quirk *quirk;
size_t i;
if (!IS_ENABLED(CONFIG_DMI))
- return -ENODATA;
+ return ERR_PTR(-ENODATA);
if (!edid)
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
for (i = 0; i < ARRAY_SIZE(drm_panel_min_backlight_quirks); i++) {
quirk = &drm_panel_min_backlight_quirks[i];
if (drm_panel_min_backlight_quirk_matches(quirk, edid))
- return quirk->min_brightness;
+ return &quirk->quirk;
}
- return -ENODATA;
+ return ERR_PTR(-ENODATA);
}
-EXPORT_SYMBOL(drm_get_panel_min_brightness_quirk);
+EXPORT_SYMBOL(drm_get_panel_backlight_quirk);
MODULE_DESCRIPTION("Quirks for panel backlight overrides");
MODULE_LICENSE("GPL");
diff --git a/include/drm/drm_utils.h b/include/drm/drm_utils.h
index 15fa9b6865f4..82eeee4a58ab 100644
--- a/include/drm/drm_utils.h
+++ b/include/drm/drm_utils.h
@@ -16,7 +16,12 @@ struct drm_edid;
int drm_get_panel_orientation_quirk(int width, int height);
-int drm_get_panel_min_brightness_quirk(const struct drm_edid *edid);
+struct drm_panel_backlight_quirk {
+ u16 min_brightness;
+};
+
+const struct drm_panel_backlight_quirk *
+drm_get_panel_backlight_quirk(const struct drm_edid *edid);
signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec);
--
2.50.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v1 3/5] drm: panel-backlight-quirks: Add secondary DMI match
2025-08-24 20:01 [PATCH v1 0/5] drm: panel-backlight-quirks: Do partial refactor and apply OLED fix Antheas Kapenekakis
2025-08-24 20:01 ` [PATCH v1 1/5] drm: panel-backlight-quirks: Make ident optional Antheas Kapenekakis
2025-08-24 20:01 ` [PATCH v1 2/5] drm: panel-backlight-quirks: Convert brightness quirk to generic structure Antheas Kapenekakis
@ 2025-08-24 20:02 ` Antheas Kapenekakis
2025-08-26 12:29 ` Philip Müller
2025-08-24 20:02 ` [PATCH v1 4/5] drm: panel-backlight-quirks: Add brightness mask quirk Antheas Kapenekakis
` (2 subsequent siblings)
5 siblings, 1 reply; 20+ messages in thread
From: Antheas Kapenekakis @ 2025-08-24 20:02 UTC (permalink / raw)
To: amd-gfx
Cc: dri-devel, linux-kernel, philm, Alex Deucher,
Christian König, Mario Limonciello, Antheas Kapenekakis
Using a single DMI match only allows matching per manufacturer.
Introduce a second optional match to allow matching make/model.
In addition, make DMI optional to allow matching only by EDID.
Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
---
drivers/gpu/drm/drm_panel_backlight_quirks.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c
index 702726c20ccc..3d386a96e50e 100644
--- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
+++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
@@ -8,11 +8,14 @@
#include <drm/drm_edid.h>
#include <drm/drm_utils.h>
+struct drm_panel_match {
+ enum dmi_field field;
+ const char * const value;
+};
+
struct drm_get_panel_backlight_quirk {
- struct {
- enum dmi_field field;
- const char * const value;
- } dmi_match;
+ struct drm_panel_match dmi_match;
+ struct drm_panel_match dmi_match_other;
struct drm_edid_ident ident;
struct drm_panel_backlight_quirk quirk;
};
@@ -48,7 +51,13 @@ static bool drm_panel_min_backlight_quirk_matches(
const struct drm_get_panel_backlight_quirk *quirk,
const struct drm_edid *edid)
{
- if (!dmi_match(quirk->dmi_match.field, quirk->dmi_match.value))
+ if (quirk->dmi_match.field &&
+ !dmi_match(quirk->dmi_match.field, quirk->dmi_match.value))
+ return false;
+
+ if (quirk->dmi_match_other.field &&
+ !dmi_match(quirk->dmi_match_other.field,
+ quirk->dmi_match_other.value))
return false;
if (quirk->ident.panel_id && !drm_edid_match(edid, &quirk->ident))
--
2.50.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v1 4/5] drm: panel-backlight-quirks: Add brightness mask quirk
2025-08-24 20:01 [PATCH v1 0/5] drm: panel-backlight-quirks: Do partial refactor and apply OLED fix Antheas Kapenekakis
` (2 preceding siblings ...)
2025-08-24 20:02 ` [PATCH v1 3/5] drm: panel-backlight-quirks: Add secondary DMI match Antheas Kapenekakis
@ 2025-08-24 20:02 ` Antheas Kapenekakis
2025-08-25 18:02 ` Mario Limonciello
2025-08-26 12:28 ` Philip Müller
2025-08-24 20:02 ` [PATCH v1 5/5] drm: panel-backlight-quirks: Add Steam Decks Antheas Kapenekakis
2025-08-25 16:45 ` [PATCH v1 0/5] drm: panel-backlight-quirks: Do partial refactor and apply OLED fix Mario Limonciello
5 siblings, 2 replies; 20+ messages in thread
From: Antheas Kapenekakis @ 2025-08-24 20:02 UTC (permalink / raw)
To: amd-gfx
Cc: dri-devel, linux-kernel, philm, Alex Deucher,
Christian König, Mario Limonciello, Antheas Kapenekakis
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. Summary examples are found below.
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
Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 +++++
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 6 ++++
drivers/gpu/drm/drm_panel_backlight_quirks.c | 29 +++++++++++++++++++
include/drm/drm_utils.h | 1 +
4 files changed, 43 insertions(+)
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 4ad80ae615a2..156f2aae6828 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3662,6 +3662,9 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
if (panel_backlight_quirk->min_brightness)
caps->min_input_signal =
panel_backlight_quirk->min_brightness - 1;
+ if (panel_backlight_quirk->brightness_mask)
+ caps->brightness_mask =
+ panel_backlight_quirk->brightness_mask;
}
}
@@ -4862,6 +4865,10 @@ static void amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm,
brightness = convert_brightness_from_user(caps, dm->brightness[bl_idx]);
link = (struct dc_link *)dm->backlight_link[bl_idx];
+ /* Apply brightness quirk */
+ if (caps->brightness_mask)
+ brightness |= caps->brightness_mask;
+
/* Change brightness based on AUX property */
mutex_lock(&dm->dc_lock);
if (dm->dc->caps.ips_support && dm->dc->ctx->dmub_srv->idle_allowed) {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index b937da0a4e4a..340f9b5f68eb 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -200,6 +200,12 @@ struct amdgpu_dm_backlight_caps {
* @aux_support: Describes if the display supports AUX backlight.
*/
bool aux_support;
+ /**
+ * @brightness_mask: After deriving brightness, or it with this mask.
+ * This is used to workaround panels that have issues with certain
+ * brightness values.
+ */
+ u32 brightness_mask;
/**
* @ac_level: the default brightness if booted on AC
*/
diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c
index 3d386a96e50e..78c430b07d6a 100644
--- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
+++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
@@ -45,6 +45,35 @@ static const struct drm_get_panel_backlight_quirk drm_panel_min_backlight_quirks
.ident.name = "NE135A1M-NY1",
.quirk = { .min_brightness = 1, },
},
+ /* Have OLED Panels with brightness issue when last byte is 0/1 */
+ {
+ .dmi_match.field = DMI_SYS_VENDOR,
+ .dmi_match.value = "AYANEO",
+ .dmi_match_other.field = DMI_PRODUCT_NAME,
+ .dmi_match_other.value = "AYANEO 3",
+ .quirk = { .brightness_mask = 3, },
+ },
+ {
+ .dmi_match.field = DMI_SYS_VENDOR,
+ .dmi_match.value = "ZOTAC",
+ .dmi_match_other.field = DMI_BOARD_NAME,
+ .dmi_match_other.value = "G0A1W",
+ .quirk = { .brightness_mask = 3, },
+ },
+ {
+ .dmi_match.field = DMI_SYS_VENDOR,
+ .dmi_match.value = "ONE-NETBOOK",
+ .dmi_match_other.field = DMI_PRODUCT_NAME,
+ .dmi_match_other.value = "ONEXPLAYER F1Pro",
+ .quirk = { .brightness_mask = 3, },
+ },
+ {
+ .dmi_match.field = DMI_SYS_VENDOR,
+ .dmi_match.value = "ONE-NETBOOK",
+ .dmi_match_other.field = DMI_PRODUCT_NAME,
+ .dmi_match_other.value = "ONEXPLAYER F1 EVA-02",
+ .quirk = { .brightness_mask = 3, },
+ }
};
static bool drm_panel_min_backlight_quirk_matches(
diff --git a/include/drm/drm_utils.h b/include/drm/drm_utils.h
index 82eeee4a58ab..6a46f755daba 100644
--- a/include/drm/drm_utils.h
+++ b/include/drm/drm_utils.h
@@ -18,6 +18,7 @@ int drm_get_panel_orientation_quirk(int width, int height);
struct drm_panel_backlight_quirk {
u16 min_brightness;
+ u32 brightness_mask;
};
const struct drm_panel_backlight_quirk *
--
2.50.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v1 5/5] drm: panel-backlight-quirks: Add Steam Decks
2025-08-24 20:01 [PATCH v1 0/5] drm: panel-backlight-quirks: Do partial refactor and apply OLED fix Antheas Kapenekakis
` (3 preceding siblings ...)
2025-08-24 20:02 ` [PATCH v1 4/5] drm: panel-backlight-quirks: Add brightness mask quirk Antheas Kapenekakis
@ 2025-08-24 20:02 ` Antheas Kapenekakis
2025-08-25 16:47 ` Mario Limonciello
2025-08-26 11:38 ` Robert Beckett
2025-08-25 16:45 ` [PATCH v1 0/5] drm: panel-backlight-quirks: Do partial refactor and apply OLED fix Mario Limonciello
5 siblings, 2 replies; 20+ messages in thread
From: Antheas Kapenekakis @ 2025-08-24 20:02 UTC (permalink / raw)
To: amd-gfx
Cc: dri-devel, linux-kernel, philm, Alex Deucher,
Christian König, Mario Limonciello, Antheas Kapenekakis
On the SteamOS kernel, Valve universally makes minimum brightness 0
for all devices. SteamOS is (was?) meant for the Steam Deck, so
enabling it universally is reasonable. However, it causes issues in
certain devices. Therefore, introduce it just for the Steam Deck here.
SteamOS kernel does not have a public mirror, but this replaces commit
806dd74bb225 ("amd/drm: override backlight min value from 12 -> 0")
in the latest, as of this writing, SteamOS kernel (6.11.11-valve24).
See unofficial mirror reconstructed from sources below.
Link: https://gitlab.com/evlaV/linux-integration/-/commit/806dd74bb225
Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
---
drivers/gpu/drm/drm_panel_backlight_quirks.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c
index 78c430b07d6a..5c24f4a86519 100644
--- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
+++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
@@ -73,7 +73,22 @@ static const struct drm_get_panel_backlight_quirk drm_panel_min_backlight_quirks
.dmi_match_other.field = DMI_PRODUCT_NAME,
.dmi_match_other.value = "ONEXPLAYER F1 EVA-02",
.quirk = { .brightness_mask = 3, },
- }
+ },
+ /* Steam Deck models */
+ {
+ .dmi_match.field = DMI_SYS_VENDOR,
+ .dmi_match.value = "Valve",
+ .dmi_match_other.field = DMI_PRODUCT_NAME,
+ .dmi_match_other.value = "Jupiter",
+ .quirk = { .min_brightness = 1, },
+ },
+ {
+ .dmi_match.field = DMI_SYS_VENDOR,
+ .dmi_match.value = "Valve",
+ .dmi_match_other.field = DMI_PRODUCT_NAME,
+ .dmi_match_other.value = "Galileo",
+ .quirk = { .min_brightness = 1, },
+ },
};
static bool drm_panel_min_backlight_quirk_matches(
--
2.50.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH v1 0/5] drm: panel-backlight-quirks: Do partial refactor and apply OLED fix
2025-08-24 20:01 [PATCH v1 0/5] drm: panel-backlight-quirks: Do partial refactor and apply OLED fix Antheas Kapenekakis
` (4 preceding siblings ...)
2025-08-24 20:02 ` [PATCH v1 5/5] drm: panel-backlight-quirks: Add Steam Decks Antheas Kapenekakis
@ 2025-08-25 16:45 ` Mario Limonciello
5 siblings, 0 replies; 20+ messages in thread
From: Mario Limonciello @ 2025-08-25 16:45 UTC (permalink / raw)
To: Antheas Kapenekakis, amd-gfx
Cc: dri-devel, linux-kernel, philm, Alex Deucher,
Christian König
On 8/24/2025 3:01 PM, Antheas Kapenekakis wrote:
> This is an alternative to [1], since Phil found out there are still invalid
> values. I made this series before the one I sent today, and I have to say
> I tested it much less. Because I did not think it was very viable to
> upstream.
I'll look through and may leave some comments on individual patches.
But I do want to say because platforms can share panels or can have
multiple sources we very likely should be keeping matching that does
SMBIOS data and panel data together.
It's also completely feasible to launch another second source or third
source panel later on which might not require the same quirks as the first.
Then lastly there are companies (IE Framework) that actively let people
change out their panel for another.
> I was also not aware of [2] and [3] since they are not in a
> public bug tracker such as amddrm and my issue there [4] remains closed.
>
> I lower the cc'd here since this is a draft.
You should make it "RFC".
> But this could have some
> viability. Especially since I can stop carrying the dodgy patches from
> SteamOS so that the SD OLED has a 0 brightness min.
>
> [1] https://lore.kernel.org/all/20250824085351.454619-2-lkml@antheas.dev/
> [2] https://gitlab.manjaro.org/packages/core/linux616/-/blob/master/0001-drm-amd-display-Add-a-quirk-for-the-Zotac-Zone.patch
> [3] https://gitlab.manjaro.org/packages/core/linux616/-/blob/master/0004-TEMPORARY-terrible-hack-for-zotac-screen-while-debug.patch
> [4] https://gitlab.freedesktop.org/drm/amd/-/issues/3803
>
> Antheas Kapenekakis (5):
> drm: panel-backlight-quirks: Make ident optional
> drm: panel-backlight-quirks: Convert brightness quirk to generic
> structure
> drm: panel-backlight-quirks: Add secondary DMI match
> drm: panel-backlight-quirks: Add brightness mask quirk
> drm: panel-backlight-quirks: Add Steam Decks
>
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 19 +++-
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 6 +
> .../link/protocols/link_edp_panel_control.c | 2 +-
> drivers/gpu/drm/drm_panel_backlight_quirks.c | 106 +++++++++++++-----
> include/drm/drm_utils.h | 8 +-
> 5 files changed, 109 insertions(+), 32 deletions(-)
>
>
> base-commit: c17b750b3ad9f45f2b6f7e6f7f4679844244f0b9
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v1 5/5] drm: panel-backlight-quirks: Add Steam Decks
2025-08-24 20:02 ` [PATCH v1 5/5] drm: panel-backlight-quirks: Add Steam Decks Antheas Kapenekakis
@ 2025-08-25 16:47 ` Mario Limonciello
2025-08-25 21:02 ` Antheas Kapenekakis
2025-08-26 11:38 ` Robert Beckett
1 sibling, 1 reply; 20+ messages in thread
From: Mario Limonciello @ 2025-08-25 16:47 UTC (permalink / raw)
To: Antheas Kapenekakis, amd-gfx
Cc: dri-devel, linux-kernel, philm, Alex Deucher,
Christian König
On 8/24/2025 3:02 PM, Antheas Kapenekakis wrote:
> On the SteamOS kernel, Valve universally makes minimum brightness 0
> for all devices. SteamOS is (was?) meant for the Steam Deck, so
> enabling it universally is reasonable. However, it causes issues in
> certain devices. Therefore, introduce it just for the Steam Deck here.
>
> SteamOS kernel does not have a public mirror, but this replaces commit
> 806dd74bb225 ("amd/drm: override backlight min value from 12 -> 0")
> in the latest, as of this writing, SteamOS kernel (6.11.11-valve24).
> See unofficial mirror reconstructed from sources below.
>
> Link: https://gitlab.com/evlaV/linux-integration/-/commit/806dd74bb225
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> ---
Directionally I agree with this commit in favor of what the downstream
kernel tree has that you linked above.
But I would rather see it sent alone and not tied to a series to
overhaul how quirks work. If it's sent alone we should be able to get
it reviewed pretty easily and in drm-misc-fixes.
> drivers/gpu/drm/drm_panel_backlight_quirks.c | 17 ++++++++++++++++-
> 1 file changed, 16 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> index 78c430b07d6a..5c24f4a86519 100644
> --- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
> +++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> @@ -73,7 +73,22 @@ static const struct drm_get_panel_backlight_quirk drm_panel_min_backlight_quirks
> .dmi_match_other.field = DMI_PRODUCT_NAME,
> .dmi_match_other.value = "ONEXPLAYER F1 EVA-02",
> .quirk = { .brightness_mask = 3, },
> - }
> + },
> + /* Steam Deck models */
> + {
> + .dmi_match.field = DMI_SYS_VENDOR,
> + .dmi_match.value = "Valve",
> + .dmi_match_other.field = DMI_PRODUCT_NAME,
> + .dmi_match_other.value = "Jupiter",
> + .quirk = { .min_brightness = 1, },
> + },
> + {
> + .dmi_match.field = DMI_SYS_VENDOR,
> + .dmi_match.value = "Valve",
> + .dmi_match_other.field = DMI_PRODUCT_NAME,
> + .dmi_match_other.value = "Galileo",
> + .quirk = { .min_brightness = 1, },
> + },
> };
>
> static bool drm_panel_min_backlight_quirk_matches(
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v1 2/5] drm: panel-backlight-quirks: Convert brightness quirk to generic structure
2025-08-24 20:01 ` [PATCH v1 2/5] drm: panel-backlight-quirks: Convert brightness quirk to generic structure Antheas Kapenekakis
@ 2025-08-25 17:53 ` Mario Limonciello
2025-08-26 12:29 ` Philip Müller
1 sibling, 0 replies; 20+ messages in thread
From: Mario Limonciello @ 2025-08-25 17:53 UTC (permalink / raw)
To: Antheas Kapenekakis, amd-gfx
Cc: dri-devel, linux-kernel, philm, Alex Deucher,
Christian König
On 8/24/2025 3:01 PM, Antheas Kapenekakis wrote:
> Currently, the brightness quirk is limited to minimum brightness only.
> Refactor it to a structure, so that more quirks can be added in the
> future. Reserve 0 value for "no quirk", and use u16 to allow minimum
> brightness up to 255.
>
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
'Conceptually' this idea makes sense to me if we do end up having a need
for new types of quirks besides minimum brightness.
> ---
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 12 ++++--
> .../link/protocols/link_edp_panel_control.c | 2 +-
> drivers/gpu/drm/drm_panel_backlight_quirks.c | 41 ++++++++++---------
> include/drm/drm_utils.h | 7 +++-
> 4 files changed, 36 insertions(+), 26 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..4ad80ae615a2 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -3612,11 +3612,11 @@ static struct drm_mode_config_helper_funcs amdgpu_dm_mode_config_helperfuncs = {
>
> static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
> {
> + const struct drm_panel_backlight_quirk *panel_backlight_quirk;
> struct amdgpu_dm_backlight_caps *caps;
> struct drm_connector *conn_base;
> struct amdgpu_device *adev;
> struct drm_luminance_range_info *luminance_range;
> - int min_input_signal_override;
>
> if (aconnector->bl_idx == -1 ||
> aconnector->dc_link->connector_signal != SIGNAL_TYPE_EDP)
> @@ -3656,9 +3656,13 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
> else
> caps->aux_min_input_signal = 1;
>
> - min_input_signal_override = drm_get_panel_min_brightness_quirk(aconnector->drm_edid);
> - if (min_input_signal_override >= 0)
> - caps->min_input_signal = min_input_signal_override;
> + panel_backlight_quirk =
> + drm_get_panel_backlight_quirk(aconnector->drm_edid);
> + if (!IS_ERR_OR_NULL(panel_backlight_quirk)) {
> + if (panel_backlight_quirk->min_brightness)
> + caps->min_input_signal =
> + panel_backlight_quirk->min_brightness - 1;
> + }
> }
>
> DEFINE_FREE(sink_release, struct dc_sink *, if (_T) dc_sink_release(_T))
> diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
> index e7927b8f5ba3..a1f37267b85e 100644
> --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
> +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
> @@ -201,7 +201,7 @@ bool edp_set_backlight_level_nits(struct dc_link *link,
> return false;
> } else if (link->backlight_control_type == BACKLIGHT_CONTROL_AMD_AUX) {
> struct dpcd_source_backlight_set dpcd_backlight_set;
> - *(uint32_t *)&dpcd_backlight_set.backlight_level_millinits = backlight_millinits;
> + *(uint32_t *)&dpcd_backlight_set.backlight_level_millinits = backlight_millinits | 3;
This seems like a spurious change that was perhaps meant to be tied to a
new conceptual quirk.
> *(uint16_t *)&dpcd_backlight_set.backlight_transition_time_ms = (uint16_t)transition_time_in_ms;
>
> uint8_t backlight_control = isHDR ? 1 : 0;
> diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> index b38b33e26ea5..702726c20ccc 100644
> --- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
> +++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> @@ -8,23 +8,23 @@
> #include <drm/drm_edid.h>
> #include <drm/drm_utils.h>
>
> -struct drm_panel_min_backlight_quirk {
> +struct drm_get_panel_backlight_quirk {
> struct {
> enum dmi_field field;
> const char * const value;
> } dmi_match;
> struct drm_edid_ident ident;
> - u8 min_brightness;
> + struct drm_panel_backlight_quirk quirk;
> };
>
> -static const struct drm_panel_min_backlight_quirk drm_panel_min_backlight_quirks[] = {
> +static const struct drm_get_panel_backlight_quirk drm_panel_min_backlight_quirks[] = {
> /* 13 inch matte panel */
> {
> .dmi_match.field = DMI_BOARD_VENDOR,
> .dmi_match.value = "Framework",
> .ident.panel_id = drm_edid_encode_panel_id('B', 'O', 'E', 0x0bca),
> .ident.name = "NE135FBM-N41",
> - .min_brightness = 0,
> + .quirk = { .min_brightness = 1, },
> },
> /* 13 inch glossy panel */
> {
> @@ -32,7 +32,7 @@ static const struct drm_panel_min_backlight_quirk drm_panel_min_backlight_quirks
> .dmi_match.value = "Framework",
> .ident.panel_id = drm_edid_encode_panel_id('B', 'O', 'E', 0x095f),
> .ident.name = "NE135FBM-N41",
> - .min_brightness = 0,
> + .quirk = { .min_brightness = 1, },
> },
> /* 13 inch 2.8k panel */
> {
> @@ -40,12 +40,13 @@ static const struct drm_panel_min_backlight_quirk drm_panel_min_backlight_quirks
> .dmi_match.value = "Framework",
> .ident.panel_id = drm_edid_encode_panel_id('B', 'O', 'E', 0x0cb4),
> .ident.name = "NE135A1M-NY1",
> - .min_brightness = 0,
> + .quirk = { .min_brightness = 1, },
> },
> };
>
> -static bool drm_panel_min_backlight_quirk_matches(const struct drm_panel_min_backlight_quirk *quirk,
> - const struct drm_edid *edid)
> +static bool drm_panel_min_backlight_quirk_matches(
> + const struct drm_get_panel_backlight_quirk *quirk,
> + const struct drm_edid *edid)
> {
> if (!dmi_match(quirk->dmi_match.field, quirk->dmi_match.value))
> return false;
> @@ -57,39 +58,39 @@ static bool drm_panel_min_backlight_quirk_matches(const struct drm_panel_min_bac
> }
>
> /**
> - * drm_get_panel_min_brightness_quirk - Get minimum supported brightness level for a panel.
> + * drm_get_panel_backlight_quirk - Get backlight quirks for a panel
> * @edid: EDID of the panel to check
> *
> * This function checks for platform specific (e.g. DMI based) quirks
> * providing info on the minimum backlight brightness for systems where this
> - * cannot be probed correctly from the hard-/firm-ware.
> + * cannot be probed correctly from the hard-/firm-ware and other sources.
> *
> * Returns:
> - * A negative error value or
> - * an override value in the range [0, 255] representing 0-100% to be scaled to
> - * the drivers target range.
> + * a drm_panel_backlight_quirk struct if a quirk was found, otherwise an
> + * error pointer.
> */
> -int drm_get_panel_min_brightness_quirk(const struct drm_edid *edid)
> +const struct drm_panel_backlight_quirk *
> +drm_get_panel_backlight_quirk(const struct drm_edid *edid)
> {
> - const struct drm_panel_min_backlight_quirk *quirk;
> + const struct drm_get_panel_backlight_quirk *quirk;
> size_t i;
>
> if (!IS_ENABLED(CONFIG_DMI))
> - return -ENODATA;
> + return ERR_PTR(-ENODATA);
>
> if (!edid)
> - return -EINVAL;
> + return ERR_PTR(-EINVAL);
>
> for (i = 0; i < ARRAY_SIZE(drm_panel_min_backlight_quirks); i++) {
> quirk = &drm_panel_min_backlight_quirks[i];
>
> if (drm_panel_min_backlight_quirk_matches(quirk, edid))
> - return quirk->min_brightness;
> + return &quirk->quirk;
> }
>
> - return -ENODATA;
> + return ERR_PTR(-ENODATA);
> }
> -EXPORT_SYMBOL(drm_get_panel_min_brightness_quirk);
> +EXPORT_SYMBOL(drm_get_panel_backlight_quirk);
>
> MODULE_DESCRIPTION("Quirks for panel backlight overrides");
> MODULE_LICENSE("GPL");
> diff --git a/include/drm/drm_utils.h b/include/drm/drm_utils.h
> index 15fa9b6865f4..82eeee4a58ab 100644
> --- a/include/drm/drm_utils.h
> +++ b/include/drm/drm_utils.h
> @@ -16,7 +16,12 @@ struct drm_edid;
>
> int drm_get_panel_orientation_quirk(int width, int height);
>
> -int drm_get_panel_min_brightness_quirk(const struct drm_edid *edid);
> +struct drm_panel_backlight_quirk {
> + u16 min_brightness;
> +};
> +
> +const struct drm_panel_backlight_quirk *
> +drm_get_panel_backlight_quirk(const struct drm_edid *edid);
>
> signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec);
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v1 4/5] drm: panel-backlight-quirks: Add brightness mask quirk
2025-08-24 20:02 ` [PATCH v1 4/5] drm: panel-backlight-quirks: Add brightness mask quirk Antheas Kapenekakis
@ 2025-08-25 18:02 ` Mario Limonciello
2025-08-25 21:17 ` Antheas Kapenekakis
2025-08-26 12:28 ` Philip Müller
1 sibling, 1 reply; 20+ messages in thread
From: Mario Limonciello @ 2025-08-25 18:02 UTC (permalink / raw)
To: Antheas Kapenekakis, amd-gfx
Cc: dri-devel, linux-kernel, philm, Alex Deucher,
Christian König
On 8/24/2025 3:02 PM, Antheas Kapenekakis wrote:
> 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
brightness
> ranges while printing DP_SOURCE_BACKLIGHT_LEVEL. It was found that
> the screen would malfunction on specific values, and some of them
> were collected. Summary examples are found below.
>
> 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
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
To me this sounds like a panel firmware bug that is best driven with the
panel vendor. But I'm guessing you're reporting it on proudution
hardware already in the field right? In the field it's basically
unheard of to update the panel firmware. The process is generally
speaking too dangerous/fragile.
So in that case a workaround would make sense. The actual issue as I'm
hearing it is that some fractional brightness values aren't working?
The API takes millinits, and I guess this was exposed by increasing the
granularity of values that userspace can program recently.
It's possible it was there before too, but there are probably "more"
values that can hit it.
> ---
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 +++++
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 6 ++++
> drivers/gpu/drm/drm_panel_backlight_quirks.c | 29 +++++++++++++++++++
> include/drm/drm_utils.h | 1 +
> 4 files changed, 43 insertions(+)
>
> 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 4ad80ae615a2..156f2aae6828 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -3662,6 +3662,9 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
> if (panel_backlight_quirk->min_brightness)
> caps->min_input_signal =
> panel_backlight_quirk->min_brightness - 1;
> + if (panel_backlight_quirk->brightness_mask)
> + caps->brightness_mask =
> + panel_backlight_quirk->brightness_mask;
> }
> }
>
> @@ -4862,6 +4865,10 @@ static void amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm,
> brightness = convert_brightness_from_user(caps, dm->brightness[bl_idx]);
> link = (struct dc_link *)dm->backlight_link[bl_idx];
>
> + /* Apply brightness quirk */
> + if (caps->brightness_mask)
> + brightness |= caps->brightness_mask;
> +
I guess a problem I could see with using a mask is that there are
basically a bunch of values that are basically becoming no-op.
An alternative would be to decrease the max value (IE some number
smaller than 65535 and scale so userspace doesn't request these "broken"
values).
I'm not sure it's worth the effort though because you will probably
still find some subset of values with this problem.
The other comment I would say is this is probably very specific to AMD
and the millinit based brightness API; it might be better to keep the
quirk localized to amdgpu. I also talked to Phil offline about this and
he's got a draft patch that helps a similar system he's seeing this on
(presumably) with another panel.
I think it's worth getting that patch onto the list and we can weigh out
the alternatives.
> /* Change brightness based on AUX property */
> mutex_lock(&dm->dc_lock);
> if (dm->dc->caps.ips_support && dm->dc->ctx->dmub_srv->idle_allowed) {
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> index b937da0a4e4a..340f9b5f68eb 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> @@ -200,6 +200,12 @@ struct amdgpu_dm_backlight_caps {
> * @aux_support: Describes if the display supports AUX backlight.
> */
> bool aux_support;
> + /**
> + * @brightness_mask: After deriving brightness, or it with this mask.
> + * This is used to workaround panels that have issues with certain
> + * brightness values.
> + */
> + u32 brightness_mask;
> /**
> * @ac_level: the default brightness if booted on AC
> */
> diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> index 3d386a96e50e..78c430b07d6a 100644
> --- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
> +++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> @@ -45,6 +45,35 @@ static const struct drm_get_panel_backlight_quirk drm_panel_min_backlight_quirks
> .ident.name = "NE135A1M-NY1",
> .quirk = { .min_brightness = 1, },
> },
> + /* Have OLED Panels with brightness issue when last byte is 0/1 */
> + {
> + .dmi_match.field = DMI_SYS_VENDOR,
> + .dmi_match.value = "AYANEO",
> + .dmi_match_other.field = DMI_PRODUCT_NAME,
> + .dmi_match_other.value = "AYANEO 3",
> + .quirk = { .brightness_mask = 3, },
> + },
> + {
> + .dmi_match.field = DMI_SYS_VENDOR,
> + .dmi_match.value = "ZOTAC",
> + .dmi_match_other.field = DMI_BOARD_NAME,
> + .dmi_match_other.value = "G0A1W",
> + .quirk = { .brightness_mask = 3, },
> + },
> + {
> + .dmi_match.field = DMI_SYS_VENDOR,
> + .dmi_match.value = "ONE-NETBOOK",
> + .dmi_match_other.field = DMI_PRODUCT_NAME,
> + .dmi_match_other.value = "ONEXPLAYER F1Pro",
> + .quirk = { .brightness_mask = 3, },
> + },
> + {
> + .dmi_match.field = DMI_SYS_VENDOR,
> + .dmi_match.value = "ONE-NETBOOK",
> + .dmi_match_other.field = DMI_PRODUCT_NAME,
> + .dmi_match_other.value = "ONEXPLAYER F1 EVA-02",
> + .quirk = { .brightness_mask = 3, },
> + }
> };
>
> static bool drm_panel_min_backlight_quirk_matches(
> diff --git a/include/drm/drm_utils.h b/include/drm/drm_utils.h
> index 82eeee4a58ab..6a46f755daba 100644
> --- a/include/drm/drm_utils.h
> +++ b/include/drm/drm_utils.h
> @@ -18,6 +18,7 @@ int drm_get_panel_orientation_quirk(int width, int height);
>
> struct drm_panel_backlight_quirk {
> u16 min_brightness;
> + u32 brightness_mask;
> };
>
> const struct drm_panel_backlight_quirk *
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v1 5/5] drm: panel-backlight-quirks: Add Steam Decks
2025-08-25 16:47 ` Mario Limonciello
@ 2025-08-25 21:02 ` Antheas Kapenekakis
2025-08-25 21:05 ` Mario Limonciello
0 siblings, 1 reply; 20+ messages in thread
From: Antheas Kapenekakis @ 2025-08-25 21:02 UTC (permalink / raw)
To: Mario Limonciello
Cc: amd-gfx, dri-devel, linux-kernel, philm, Alex Deucher,
Christian König
On Mon, 25 Aug 2025 at 18:47, Mario Limonciello
<mario.limonciello@amd.com> wrote:
>
> On 8/24/2025 3:02 PM, Antheas Kapenekakis wrote:
> > On the SteamOS kernel, Valve universally makes minimum brightness 0
> > for all devices. SteamOS is (was?) meant for the Steam Deck, so
> > enabling it universally is reasonable. However, it causes issues in
> > certain devices. Therefore, introduce it just for the Steam Deck here.
> >
> > SteamOS kernel does not have a public mirror, but this replaces commit
> > 806dd74bb225 ("amd/drm: override backlight min value from 12 -> 0")
> > in the latest, as of this writing, SteamOS kernel (6.11.11-valve24).
> > See unofficial mirror reconstructed from sources below.
> >
> > Link: https://gitlab.com/evlaV/linux-integration/-/commit/806dd74bb225
> > Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> > ---
>
> Directionally I agree with this commit in favor of what the downstream
> kernel tree has that you linked above.
>
> But I would rather see it sent alone and not tied to a series to
> overhaul how quirks work. If it's sent alone we should be able to get
> it reviewed pretty easily and in drm-misc-fixes.
That's a good idea. However, this commit relies on patch 1 and 3, as
it has no edid information and uses a second match.
Antheas
> > drivers/gpu/drm/drm_panel_backlight_quirks.c | 17 ++++++++++++++++-
> > 1 file changed, 16 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> > index 78c430b07d6a..5c24f4a86519 100644
> > --- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
> > +++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> > @@ -73,7 +73,22 @@ static const struct drm_get_panel_backlight_quirk drm_panel_min_backlight_quirks
> > .dmi_match_other.field = DMI_PRODUCT_NAME,
> > .dmi_match_other.value = "ONEXPLAYER F1 EVA-02",
> > .quirk = { .brightness_mask = 3, },
> > - }
> > + },
> > + /* Steam Deck models */
> > + {
> > + .dmi_match.field = DMI_SYS_VENDOR,
> > + .dmi_match.value = "Valve",
> > + .dmi_match_other.field = DMI_PRODUCT_NAME,
> > + .dmi_match_other.value = "Jupiter",
> > + .quirk = { .min_brightness = 1, },
> > + },
> > + {
> > + .dmi_match.field = DMI_SYS_VENDOR,
> > + .dmi_match.value = "Valve",
> > + .dmi_match_other.field = DMI_PRODUCT_NAME,
> > + .dmi_match_other.value = "Galileo",
> > + .quirk = { .min_brightness = 1, },
> > + },
> > };
> >
> > static bool drm_panel_min_backlight_quirk_matches(
>
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v1 5/5] drm: panel-backlight-quirks: Add Steam Decks
2025-08-25 21:02 ` Antheas Kapenekakis
@ 2025-08-25 21:05 ` Mario Limonciello
2025-08-25 21:20 ` Antheas Kapenekakis
0 siblings, 1 reply; 20+ messages in thread
From: Mario Limonciello @ 2025-08-25 21:05 UTC (permalink / raw)
To: Antheas Kapenekakis
Cc: amd-gfx, dri-devel, linux-kernel, philm, Alex Deucher,
Christian König
On 8/25/2025 4:02 PM, Antheas Kapenekakis wrote:
> On Mon, 25 Aug 2025 at 18:47, Mario Limonciello
> <mario.limonciello@amd.com> wrote:
>>
>> On 8/24/2025 3:02 PM, Antheas Kapenekakis wrote:
>>> On the SteamOS kernel, Valve universally makes minimum brightness 0
>>> for all devices. SteamOS is (was?) meant for the Steam Deck, so
>>> enabling it universally is reasonable. However, it causes issues in
>>> certain devices. Therefore, introduce it just for the Steam Deck here.
>>>
>>> SteamOS kernel does not have a public mirror, but this replaces commit
>>> 806dd74bb225 ("amd/drm: override backlight min value from 12 -> 0")
>>> in the latest, as of this writing, SteamOS kernel (6.11.11-valve24).
>>> See unofficial mirror reconstructed from sources below.
>>>
>>> Link: https://gitlab.com/evlaV/linux-integration/-/commit/806dd74bb225
>>> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
>>> ---
>>
>> Directionally I agree with this commit in favor of what the downstream
>> kernel tree has that you linked above.
>>
>> But I would rather see it sent alone and not tied to a series to
>> overhaul how quirks work. If it's sent alone we should be able to get
>> it reviewed pretty easily and in drm-misc-fixes.
>
> That's a good idea. However, this commit relies on patch 1 and 3, as
> it has no edid information and uses a second match.
The EDID half should be a solvable problem. IE the EDIDs for Steam Deck
and Steam Deck OLED are known quantities, or a least trivial to dump.
And once you have the EDID in place I'm not sure if you need a second
match anymore or not really (at least for SD/SD OLED).
>
> Antheas
>
>>> drivers/gpu/drm/drm_panel_backlight_quirks.c | 17 ++++++++++++++++-
>>> 1 file changed, 16 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c
>>> index 78c430b07d6a..5c24f4a86519 100644
>>> --- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
>>> +++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
>>> @@ -73,7 +73,22 @@ static const struct drm_get_panel_backlight_quirk drm_panel_min_backlight_quirks
>>> .dmi_match_other.field = DMI_PRODUCT_NAME,
>>> .dmi_match_other.value = "ONEXPLAYER F1 EVA-02",
>>> .quirk = { .brightness_mask = 3, },
>>> - }
>>> + },
>>> + /* Steam Deck models */
>>> + {
>>> + .dmi_match.field = DMI_SYS_VENDOR,
>>> + .dmi_match.value = "Valve",
>>> + .dmi_match_other.field = DMI_PRODUCT_NAME,
>>> + .dmi_match_other.value = "Jupiter",
>>> + .quirk = { .min_brightness = 1, },
>>> + },
>>> + {
>>> + .dmi_match.field = DMI_SYS_VENDOR,
>>> + .dmi_match.value = "Valve",
>>> + .dmi_match_other.field = DMI_PRODUCT_NAME,
>>> + .dmi_match_other.value = "Galileo",
>>> + .quirk = { .min_brightness = 1, },
>>> + },
>>> };
>>>
>>> static bool drm_panel_min_backlight_quirk_matches(
>>
>>
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v1 4/5] drm: panel-backlight-quirks: Add brightness mask quirk
2025-08-25 18:02 ` Mario Limonciello
@ 2025-08-25 21:17 ` Antheas Kapenekakis
2025-08-25 21:22 ` Mario Limonciello
0 siblings, 1 reply; 20+ messages in thread
From: Antheas Kapenekakis @ 2025-08-25 21:17 UTC (permalink / raw)
To: Mario Limonciello
Cc: amd-gfx, dri-devel, linux-kernel, philm, Alex Deucher,
Christian König
On Mon, 25 Aug 2025 at 20:02, Mario Limonciello
<mario.limonciello@amd.com> wrote:
>
> On 8/24/2025 3:02 PM, Antheas Kapenekakis wrote:
> > 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
>
> brightness
>
> > ranges while printing DP_SOURCE_BACKLIGHT_LEVEL. It was found that
> > the screen would malfunction on specific values, and some of them
> > were collected. Summary examples are found below.
> >
> > 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
> > Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
>
> To me this sounds like a panel firmware bug that is best driven with the
> panel vendor. But I'm guessing you're reporting it on proudution
> hardware already in the field right? In the field it's basically
> unheard of to update the panel firmware. The process is generally
> speaking too dangerous/fragile.
>
> So in that case a workaround would make sense. The actual issue as I'm
> hearing it is that some fractional brightness values aren't working?
> The API takes millinits, and I guess this was exposed by increasing the
> granularity of values that userspace can program recently.
>
> It's possible it was there before too, but there are probably "more"
> values that can hit it.
Yes, it seems like if the first byte is 0 (always) or 1 (sometimes)
then the panel turns off. The patch that forces using 100mnits works
fully in my testing but Phil can still hit values on his device.
Perhaps at a 1nit or 2 nit accuracy all the values are ok which is why
Windows works fine
It has already shipped in 4 SKUs from 3 manufacturers as shown below.
>
> > ---
> > .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 +++++
> > .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 6 ++++
> > drivers/gpu/drm/drm_panel_backlight_quirks.c | 29 +++++++++++++++++++
> > include/drm/drm_utils.h | 1 +
> > 4 files changed, 43 insertions(+)
> >
> > 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 4ad80ae615a2..156f2aae6828 100644
> > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> > @@ -3662,6 +3662,9 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
> > if (panel_backlight_quirk->min_brightness)
> > caps->min_input_signal =
> > panel_backlight_quirk->min_brightness - 1;
> > + if (panel_backlight_quirk->brightness_mask)
> > + caps->brightness_mask =
> > + panel_backlight_quirk->brightness_mask;
> > }
> > }
> >
> > @@ -4862,6 +4865,10 @@ static void amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm,
> > brightness = convert_brightness_from_user(caps, dm->brightness[bl_idx]);
> > link = (struct dc_link *)dm->backlight_link[bl_idx];
> >
> > + /* Apply brightness quirk */
> > + if (caps->brightness_mask)
> > + brightness |= caps->brightness_mask;
> > +
>
> I guess a problem I could see with using a mask is that there are
> basically a bunch of values that are basically becoming no-op.
Yeah, 1/3, but those were noops anyway, because 3mnit is not much.
> An alternative would be to decrease the max value (IE some number
> smaller than 65535 and scale so userspace doesn't request these "broken"
> values).
>
> I'm not sure it's worth the effort though because you will probably
> still find some subset of values with this problem.
The patch that was with the VPE quirk essentially does that and works
really well. But it is not perfect. That's at 100mnits.
> The other comment I would say is this is probably very specific to AMD
> and the millinit based brightness API; it might be better to keep the
> quirk localized to amdgpu. I also talked to Phil offline about this and
> he's got a draft patch that helps a similar system he's seeing this on
> (presumably) with another panel.
>
> I think it's worth getting that patch onto the list and we can weigh out
> the alternatives.
I think it is the same panel spec. Perhaps it is a different factory,
but all affected devices are 7in OLED 1080p portrait panels with HDR.
I sent this patch before I cleaned it up fully because Phil wanted to
test it. It seems to work well. I think he's looking into implementing
the same quirk essentially.
I would not say it is specific to AMD per say. The bug happens in the
panel after being sent a command to set the brightness through a
shared drm helper. The same panel on intel with the same value would
have the same problem. Perhaps not depending on the backlight code
that preprocesses the values. The drm_panel_backlight_quirks is used
only by amd currently in any case. And this quirk system allows
specifying EDID information, where the DRM code one that you did did
not. I only saw that after I had made this series.
Antheas
> > /* Change brightness based on AUX property */
> > mutex_lock(&dm->dc_lock);
> > if (dm->dc->caps.ips_support && dm->dc->ctx->dmub_srv->idle_allowed) {
> > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> > index b937da0a4e4a..340f9b5f68eb 100644
> > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> > @@ -200,6 +200,12 @@ struct amdgpu_dm_backlight_caps {
> > * @aux_support: Describes if the display supports AUX backlight.
> > */
> > bool aux_support;
> > + /**
> > + * @brightness_mask: After deriving brightness, or it with this mask.
> > + * This is used to workaround panels that have issues with certain
> > + * brightness values.
> > + */
> > + u32 brightness_mask;
> > /**
> > * @ac_level: the default brightness if booted on AC
> > */
> > diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> > index 3d386a96e50e..78c430b07d6a 100644
> > --- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
> > +++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> > @@ -45,6 +45,35 @@ static const struct drm_get_panel_backlight_quirk drm_panel_min_backlight_quirks
> > .ident.name = "NE135A1M-NY1",
> > .quirk = { .min_brightness = 1, },
> > },
> > + /* Have OLED Panels with brightness issue when last byte is 0/1 */
> > + {
> > + .dmi_match.field = DMI_SYS_VENDOR,
> > + .dmi_match.value = "AYANEO",
> > + .dmi_match_other.field = DMI_PRODUCT_NAME,
> > + .dmi_match_other.value = "AYANEO 3",
> > + .quirk = { .brightness_mask = 3, },
> > + },
> > + {
> > + .dmi_match.field = DMI_SYS_VENDOR,
> > + .dmi_match.value = "ZOTAC",
> > + .dmi_match_other.field = DMI_BOARD_NAME,
> > + .dmi_match_other.value = "G0A1W",
> > + .quirk = { .brightness_mask = 3, },
> > + },
> > + {
> > + .dmi_match.field = DMI_SYS_VENDOR,
> > + .dmi_match.value = "ONE-NETBOOK",
> > + .dmi_match_other.field = DMI_PRODUCT_NAME,
> > + .dmi_match_other.value = "ONEXPLAYER F1Pro",
> > + .quirk = { .brightness_mask = 3, },
> > + },
> > + {
> > + .dmi_match.field = DMI_SYS_VENDOR,
> > + .dmi_match.value = "ONE-NETBOOK",
> > + .dmi_match_other.field = DMI_PRODUCT_NAME,
> > + .dmi_match_other.value = "ONEXPLAYER F1 EVA-02",
> > + .quirk = { .brightness_mask = 3, },
> > + }
> > };
> >
> > static bool drm_panel_min_backlight_quirk_matches(
> > diff --git a/include/drm/drm_utils.h b/include/drm/drm_utils.h
> > index 82eeee4a58ab..6a46f755daba 100644
> > --- a/include/drm/drm_utils.h
> > +++ b/include/drm/drm_utils.h
> > @@ -18,6 +18,7 @@ int drm_get_panel_orientation_quirk(int width, int height);
> >
> > struct drm_panel_backlight_quirk {
> > u16 min_brightness;
> > + u32 brightness_mask;
> > };
> >
> > const struct drm_panel_backlight_quirk *
>
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v1 5/5] drm: panel-backlight-quirks: Add Steam Decks
2025-08-25 21:05 ` Mario Limonciello
@ 2025-08-25 21:20 ` Antheas Kapenekakis
0 siblings, 0 replies; 20+ messages in thread
From: Antheas Kapenekakis @ 2025-08-25 21:20 UTC (permalink / raw)
To: Mario Limonciello
Cc: amd-gfx, dri-devel, linux-kernel, philm, Alex Deucher,
Christian König
On Mon, 25 Aug 2025 at 23:05, Mario Limonciello
<mario.limonciello@amd.com> wrote:
>
> On 8/25/2025 4:02 PM, Antheas Kapenekakis wrote:
> > On Mon, 25 Aug 2025 at 18:47, Mario Limonciello
> > <mario.limonciello@amd.com> wrote:
> >>
> >> On 8/24/2025 3:02 PM, Antheas Kapenekakis wrote:
> >>> On the SteamOS kernel, Valve universally makes minimum brightness 0
> >>> for all devices. SteamOS is (was?) meant for the Steam Deck, so
> >>> enabling it universally is reasonable. However, it causes issues in
> >>> certain devices. Therefore, introduce it just for the Steam Deck here.
> >>>
> >>> SteamOS kernel does not have a public mirror, but this replaces commit
> >>> 806dd74bb225 ("amd/drm: override backlight min value from 12 -> 0")
> >>> in the latest, as of this writing, SteamOS kernel (6.11.11-valve24).
> >>> See unofficial mirror reconstructed from sources below.
> >>>
> >>> Link: https://gitlab.com/evlaV/linux-integration/-/commit/806dd74bb225
> >>> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> >>> ---
> >>
> >> Directionally I agree with this commit in favor of what the downstream
> >> kernel tree has that you linked above.
> >>
> >> But I would rather see it sent alone and not tied to a series to
> >> overhaul how quirks work. If it's sent alone we should be able to get
> >> it reviewed pretty easily and in drm-misc-fixes.
> >
> > That's a good idea. However, this commit relies on patch 1 and 3, as
> > it has no edid information and uses a second match.
>
> The EDID half should be a solvable problem. IE the EDIDs for Steam Deck
> and Steam Deck OLED are known quantities, or a least trivial to dump.
>
> And once you have the EDID in place I'm not sure if you need a second
> match anymore or not really (at least for SD/SD OLED).
Yeah. Perhaps for those you are right. The information should be in
gamescope in github. I think there are four panels.
I need to start logging edid information on bug reports though,
otherwise I would not say it is trivial, esp. for the four devices
that need the luminance quirk.
> >
> > Antheas
> >
> >>> drivers/gpu/drm/drm_panel_backlight_quirks.c | 17 ++++++++++++++++-
> >>> 1 file changed, 16 insertions(+), 1 deletion(-)
> >>>
> >>> diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> >>> index 78c430b07d6a..5c24f4a86519 100644
> >>> --- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
> >>> +++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> >>> @@ -73,7 +73,22 @@ static const struct drm_get_panel_backlight_quirk drm_panel_min_backlight_quirks
> >>> .dmi_match_other.field = DMI_PRODUCT_NAME,
> >>> .dmi_match_other.value = "ONEXPLAYER F1 EVA-02",
> >>> .quirk = { .brightness_mask = 3, },
> >>> - }
> >>> + },
> >>> + /* Steam Deck models */
> >>> + {
> >>> + .dmi_match.field = DMI_SYS_VENDOR,
> >>> + .dmi_match.value = "Valve",
> >>> + .dmi_match_other.field = DMI_PRODUCT_NAME,
> >>> + .dmi_match_other.value = "Jupiter",
> >>> + .quirk = { .min_brightness = 1, },
> >>> + },
> >>> + {
> >>> + .dmi_match.field = DMI_SYS_VENDOR,
> >>> + .dmi_match.value = "Valve",
> >>> + .dmi_match_other.field = DMI_PRODUCT_NAME,
> >>> + .dmi_match_other.value = "Galileo",
> >>> + .quirk = { .min_brightness = 1, },
> >>> + },
> >>> };
> >>>
> >>> static bool drm_panel_min_backlight_quirk_matches(
> >>
> >>
> >
>
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v1 4/5] drm: panel-backlight-quirks: Add brightness mask quirk
2025-08-25 21:17 ` Antheas Kapenekakis
@ 2025-08-25 21:22 ` Mario Limonciello
2025-08-25 21:26 ` Antheas Kapenekakis
0 siblings, 1 reply; 20+ messages in thread
From: Mario Limonciello @ 2025-08-25 21:22 UTC (permalink / raw)
To: Antheas Kapenekakis
Cc: amd-gfx, dri-devel, linux-kernel, philm, Alex Deucher,
Christian König
On 8/25/2025 4:17 PM, Antheas Kapenekakis wrote:
> On Mon, 25 Aug 2025 at 20:02, Mario Limonciello
> <mario.limonciello@amd.com> wrote:
>>
>> On 8/24/2025 3:02 PM, Antheas Kapenekakis wrote:
>>> 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
>>
>> brightness
>>
>>> ranges while printing DP_SOURCE_BACKLIGHT_LEVEL. It was found that
>>> the screen would malfunction on specific values, and some of them
>>> were collected. Summary examples are found below.
>>>
>>> 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
>>> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
>>
>> To me this sounds like a panel firmware bug that is best driven with the
>> panel vendor. But I'm guessing you're reporting it on proudution
>> hardware already in the field right? In the field it's basically
>> unheard of to update the panel firmware. The process is generally
>> speaking too dangerous/fragile.
>>
>> So in that case a workaround would make sense. The actual issue as I'm
>> hearing it is that some fractional brightness values aren't working?
>> The API takes millinits, and I guess this was exposed by increasing the
>> granularity of values that userspace can program recently.
>>
>> It's possible it was there before too, but there are probably "more"
>> values that can hit it.
>
> Yes, it seems like if the first byte is 0 (always) or 1 (sometimes)
> then the panel turns off. The patch that forces using 100mnits works
> fully in my testing but Phil can still hit values on his device.
> Perhaps at a 1nit or 2 nit accuracy all the values are ok which is why
> Windows works fine
>
> It has already shipped in 4 SKUs from 3 manufacturers as shown below.
>
>>
>>> ---
>>> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 +++++
>>> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 6 ++++
>>> drivers/gpu/drm/drm_panel_backlight_quirks.c | 29 +++++++++++++++++++
>>> include/drm/drm_utils.h | 1 +
>>> 4 files changed, 43 insertions(+)
>>>
>>> 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 4ad80ae615a2..156f2aae6828 100644
>>> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
>>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
>>> @@ -3662,6 +3662,9 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
>>> if (panel_backlight_quirk->min_brightness)
>>> caps->min_input_signal =
>>> panel_backlight_quirk->min_brightness - 1;
>>> + if (panel_backlight_quirk->brightness_mask)
>>> + caps->brightness_mask =
>>> + panel_backlight_quirk->brightness_mask;
>>> }
>>> }
>>>
>>> @@ -4862,6 +4865,10 @@ static void amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm,
>>> brightness = convert_brightness_from_user(caps, dm->brightness[bl_idx]);
>>> link = (struct dc_link *)dm->backlight_link[bl_idx];
>>>
>>> + /* Apply brightness quirk */
>>> + if (caps->brightness_mask)
>>> + brightness |= caps->brightness_mask;
>>> +
>>
>> I guess a problem I could see with using a mask is that there are
>> basically a bunch of values that are basically becoming no-op.
>
> Yeah, 1/3, but those were noops anyway, because 3mnit is not much.
>
>> An alternative would be to decrease the max value (IE some number
>> smaller than 65535 and scale so userspace doesn't request these "broken"
>> values).
>>
>> I'm not sure it's worth the effort though because you will probably
>> still find some subset of values with this problem.
>
> The patch that was with the VPE quirk essentially does that and works
> really well. But it is not perfect. That's at 100mnits.
>
>> The other comment I would say is this is probably very specific to AMD
>> and the millinit based brightness API; it might be better to keep the
>> quirk localized to amdgpu. I also talked to Phil offline about this and
>> he's got a draft patch that helps a similar system he's seeing this on
>> (presumably) with another panel.
>>
>> I think it's worth getting that patch onto the list and we can weigh out
>> the alternatives.
>
> I think it is the same panel spec. Perhaps it is a different factory,
> but all affected devices are 7in OLED 1080p portrait panels with HDR.
> I sent this patch before I cleaned it up fully because Phil wanted to
> test it. It seems to work well. I think he's looking into implementing
> the same quirk essentially.
>
> I would not say it is specific to AMD per say. The bug happens in the
> panel after being sent a command to set the brightness through a
> shared drm helper. The same panel on intel with the same value would
> have the same problem.
Does Intel also have millinits brightness control? I wasn't sure.
> Perhaps not depending on the backlight code
> that preprocesses the values. The drm_panel_backlight_quirks is used
> only by amd currently in any case. And this quirk system allows
> specifying EDID information, where the DRM code one that you did did
> not. I only saw that after I had made this series.
>
> Antheas
OK thanks. As you and Phil both have affected devices that are very
similar result get offline with Phil and come together with a new patch
series that works for both of you via quirks.
>
>
>>> /* Change brightness based on AUX property */
>>> mutex_lock(&dm->dc_lock);
>>> if (dm->dc->caps.ips_support && dm->dc->ctx->dmub_srv->idle_allowed) {
>>> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
>>> index b937da0a4e4a..340f9b5f68eb 100644
>>> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
>>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
>>> @@ -200,6 +200,12 @@ struct amdgpu_dm_backlight_caps {
>>> * @aux_support: Describes if the display supports AUX backlight.
>>> */
>>> bool aux_support;
>>> + /**
>>> + * @brightness_mask: After deriving brightness, or it with this mask.
>>> + * This is used to workaround panels that have issues with certain
>>> + * brightness values.
>>> + */
>>> + u32 brightness_mask;
>>> /**
>>> * @ac_level: the default brightness if booted on AC
>>> */
>>> diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c
>>> index 3d386a96e50e..78c430b07d6a 100644
>>> --- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
>>> +++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
>>> @@ -45,6 +45,35 @@ static const struct drm_get_panel_backlight_quirk drm_panel_min_backlight_quirks
>>> .ident.name = "NE135A1M-NY1",
>>> .quirk = { .min_brightness = 1, },
>>> },
>>> + /* Have OLED Panels with brightness issue when last byte is 0/1 */
>>> + {
>>> + .dmi_match.field = DMI_SYS_VENDOR,
>>> + .dmi_match.value = "AYANEO",
>>> + .dmi_match_other.field = DMI_PRODUCT_NAME,
>>> + .dmi_match_other.value = "AYANEO 3",
>>> + .quirk = { .brightness_mask = 3, },
>>> + },
>>> + {
>>> + .dmi_match.field = DMI_SYS_VENDOR,
>>> + .dmi_match.value = "ZOTAC",
>>> + .dmi_match_other.field = DMI_BOARD_NAME,
>>> + .dmi_match_other.value = "G0A1W",
>>> + .quirk = { .brightness_mask = 3, },
>>> + },
>>> + {
>>> + .dmi_match.field = DMI_SYS_VENDOR,
>>> + .dmi_match.value = "ONE-NETBOOK",
>>> + .dmi_match_other.field = DMI_PRODUCT_NAME,
>>> + .dmi_match_other.value = "ONEXPLAYER F1Pro",
>>> + .quirk = { .brightness_mask = 3, },
>>> + },
>>> + {
>>> + .dmi_match.field = DMI_SYS_VENDOR,
>>> + .dmi_match.value = "ONE-NETBOOK",
>>> + .dmi_match_other.field = DMI_PRODUCT_NAME,
>>> + .dmi_match_other.value = "ONEXPLAYER F1 EVA-02",
>>> + .quirk = { .brightness_mask = 3, },
>>> + }
>>> };
>>>
>>> static bool drm_panel_min_backlight_quirk_matches(
>>> diff --git a/include/drm/drm_utils.h b/include/drm/drm_utils.h
>>> index 82eeee4a58ab..6a46f755daba 100644
>>> --- a/include/drm/drm_utils.h
>>> +++ b/include/drm/drm_utils.h
>>> @@ -18,6 +18,7 @@ int drm_get_panel_orientation_quirk(int width, int height);
>>>
>>> struct drm_panel_backlight_quirk {
>>> u16 min_brightness;
>>> + u32 brightness_mask;
>>> };
>>>
>>> const struct drm_panel_backlight_quirk *
>>
>>
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v1 4/5] drm: panel-backlight-quirks: Add brightness mask quirk
2025-08-25 21:22 ` Mario Limonciello
@ 2025-08-25 21:26 ` Antheas Kapenekakis
0 siblings, 0 replies; 20+ messages in thread
From: Antheas Kapenekakis @ 2025-08-25 21:26 UTC (permalink / raw)
To: Mario Limonciello
Cc: amd-gfx, dri-devel, linux-kernel, philm, Alex Deucher,
Christian König
On Mon, 25 Aug 2025 at 23:22, Mario Limonciello
<mario.limonciello@amd.com> wrote:
>
> On 8/25/2025 4:17 PM, Antheas Kapenekakis wrote:
> > On Mon, 25 Aug 2025 at 20:02, Mario Limonciello
> > <mario.limonciello@amd.com> wrote:
> >>
> >> On 8/24/2025 3:02 PM, Antheas Kapenekakis wrote:
> >>> 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
> >>
> >> brightness
> >>
> >>> ranges while printing DP_SOURCE_BACKLIGHT_LEVEL. It was found that
> >>> the screen would malfunction on specific values, and some of them
> >>> were collected. Summary examples are found below.
> >>>
> >>> 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
> >>> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> >>
> >> To me this sounds like a panel firmware bug that is best driven with the
> >> panel vendor. But I'm guessing you're reporting it on proudution
> >> hardware already in the field right? In the field it's basically
> >> unheard of to update the panel firmware. The process is generally
> >> speaking too dangerous/fragile.
> >>
> >> So in that case a workaround would make sense. The actual issue as I'm
> >> hearing it is that some fractional brightness values aren't working?
> >> The API takes millinits, and I guess this was exposed by increasing the
> >> granularity of values that userspace can program recently.
> >>
> >> It's possible it was there before too, but there are probably "more"
> >> values that can hit it.
> >
> > Yes, it seems like if the first byte is 0 (always) or 1 (sometimes)
> > then the panel turns off. The patch that forces using 100mnits works
> > fully in my testing but Phil can still hit values on his device.
> > Perhaps at a 1nit or 2 nit accuracy all the values are ok which is why
> > Windows works fine
> >
> > It has already shipped in 4 SKUs from 3 manufacturers as shown below.
> >
> >>
> >>> ---
> >>> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 +++++
> >>> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 6 ++++
> >>> drivers/gpu/drm/drm_panel_backlight_quirks.c | 29 +++++++++++++++++++
> >>> include/drm/drm_utils.h | 1 +
> >>> 4 files changed, 43 insertions(+)
> >>>
> >>> 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 4ad80ae615a2..156f2aae6828 100644
> >>> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> >>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> >>> @@ -3662,6 +3662,9 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
> >>> if (panel_backlight_quirk->min_brightness)
> >>> caps->min_input_signal =
> >>> panel_backlight_quirk->min_brightness - 1;
> >>> + if (panel_backlight_quirk->brightness_mask)
> >>> + caps->brightness_mask =
> >>> + panel_backlight_quirk->brightness_mask;
> >>> }
> >>> }
> >>>
> >>> @@ -4862,6 +4865,10 @@ static void amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm,
> >>> brightness = convert_brightness_from_user(caps, dm->brightness[bl_idx]);
> >>> link = (struct dc_link *)dm->backlight_link[bl_idx];
> >>>
> >>> + /* Apply brightness quirk */
> >>> + if (caps->brightness_mask)
> >>> + brightness |= caps->brightness_mask;
> >>> +
> >>
> >> I guess a problem I could see with using a mask is that there are
> >> basically a bunch of values that are basically becoming no-op.
> >
> > Yeah, 1/3, but those were noops anyway, because 3mnit is not much.
> >
> >> An alternative would be to decrease the max value (IE some number
> >> smaller than 65535 and scale so userspace doesn't request these "broken"
> >> values).
> >>
> >> I'm not sure it's worth the effort though because you will probably
> >> still find some subset of values with this problem.
> >
> > The patch that was with the VPE quirk essentially does that and works
> > really well. But it is not perfect. That's at 100mnits.
> >
> >> The other comment I would say is this is probably very specific to AMD
> >> and the millinit based brightness API; it might be better to keep the
> >> quirk localized to amdgpu. I also talked to Phil offline about this and
> >> he's got a draft patch that helps a similar system he's seeing this on
> >> (presumably) with another panel.
> >>
> >> I think it's worth getting that patch onto the list and we can weigh out
> >> the alternatives.
> >
> > I think it is the same panel spec. Perhaps it is a different factory,
> > but all affected devices are 7in OLED 1080p portrait panels with HDR.
> > I sent this patch before I cleaned it up fully because Phil wanted to
> > test it. It seems to work well. I think he's looking into implementing
> > the same quirk essentially.
> >
> > I would not say it is specific to AMD per say. The bug happens in the
> > panel after being sent a command to set the brightness through a
> > shared drm helper. The same panel on intel with the same value would
> > have the same problem.
>
> Does Intel also have millinits brightness control? I wasn't sure.
Hm maybe I am wrong on this one. BACKLIGHT_CONTROL_AMD/VESA_AUX seem
AMD specific.
> > Perhaps not depending on the backlight code
> > that preprocesses the values. The drm_panel_backlight_quirks is used
> > only by amd currently in any case. And this quirk system allows
> > specifying EDID information, where the DRM code one that you did did
> > not. I only saw that after I had made this series.
> >
> > Antheas
>
> OK thanks. As you and Phil both have affected devices that are very
> similar result get offline with Phil and come together with a new patch
> series that works for both of you via quirks.
>
> >
> >
> >>> /* Change brightness based on AUX property */
> >>> mutex_lock(&dm->dc_lock);
> >>> if (dm->dc->caps.ips_support && dm->dc->ctx->dmub_srv->idle_allowed) {
> >>> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> >>> index b937da0a4e4a..340f9b5f68eb 100644
> >>> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> >>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> >>> @@ -200,6 +200,12 @@ struct amdgpu_dm_backlight_caps {
> >>> * @aux_support: Describes if the display supports AUX backlight.
> >>> */
> >>> bool aux_support;
> >>> + /**
> >>> + * @brightness_mask: After deriving brightness, or it with this mask.
> >>> + * This is used to workaround panels that have issues with certain
> >>> + * brightness values.
> >>> + */
> >>> + u32 brightness_mask;
> >>> /**
> >>> * @ac_level: the default brightness if booted on AC
> >>> */
> >>> diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> >>> index 3d386a96e50e..78c430b07d6a 100644
> >>> --- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
> >>> +++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> >>> @@ -45,6 +45,35 @@ static const struct drm_get_panel_backlight_quirk drm_panel_min_backlight_quirks
> >>> .ident.name = "NE135A1M-NY1",
> >>> .quirk = { .min_brightness = 1, },
> >>> },
> >>> + /* Have OLED Panels with brightness issue when last byte is 0/1 */
> >>> + {
> >>> + .dmi_match.field = DMI_SYS_VENDOR,
> >>> + .dmi_match.value = "AYANEO",
> >>> + .dmi_match_other.field = DMI_PRODUCT_NAME,
> >>> + .dmi_match_other.value = "AYANEO 3",
> >>> + .quirk = { .brightness_mask = 3, },
> >>> + },
> >>> + {
> >>> + .dmi_match.field = DMI_SYS_VENDOR,
> >>> + .dmi_match.value = "ZOTAC",
> >>> + .dmi_match_other.field = DMI_BOARD_NAME,
> >>> + .dmi_match_other.value = "G0A1W",
> >>> + .quirk = { .brightness_mask = 3, },
> >>> + },
> >>> + {
> >>> + .dmi_match.field = DMI_SYS_VENDOR,
> >>> + .dmi_match.value = "ONE-NETBOOK",
> >>> + .dmi_match_other.field = DMI_PRODUCT_NAME,
> >>> + .dmi_match_other.value = "ONEXPLAYER F1Pro",
> >>> + .quirk = { .brightness_mask = 3, },
> >>> + },
> >>> + {
> >>> + .dmi_match.field = DMI_SYS_VENDOR,
> >>> + .dmi_match.value = "ONE-NETBOOK",
> >>> + .dmi_match_other.field = DMI_PRODUCT_NAME,
> >>> + .dmi_match_other.value = "ONEXPLAYER F1 EVA-02",
> >>> + .quirk = { .brightness_mask = 3, },
> >>> + }
> >>> };
> >>>
> >>> static bool drm_panel_min_backlight_quirk_matches(
> >>> diff --git a/include/drm/drm_utils.h b/include/drm/drm_utils.h
> >>> index 82eeee4a58ab..6a46f755daba 100644
> >>> --- a/include/drm/drm_utils.h
> >>> +++ b/include/drm/drm_utils.h
> >>> @@ -18,6 +18,7 @@ int drm_get_panel_orientation_quirk(int width, int height);
> >>>
> >>> struct drm_panel_backlight_quirk {
> >>> u16 min_brightness;
> >>> + u32 brightness_mask;
> >>> };
> >>>
> >>> const struct drm_panel_backlight_quirk *
> >>
> >>
> >
>
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v1 5/5] drm: panel-backlight-quirks: Add Steam Decks
2025-08-24 20:02 ` [PATCH v1 5/5] drm: panel-backlight-quirks: Add Steam Decks Antheas Kapenekakis
2025-08-25 16:47 ` Mario Limonciello
@ 2025-08-26 11:38 ` Robert Beckett
1 sibling, 0 replies; 20+ messages in thread
From: Robert Beckett @ 2025-08-26 11:38 UTC (permalink / raw)
To: Antheas Kapenekakis
Cc: amd-gfx, dri-devel, linux-kernel, philm, Alex Deucher,
"Christian König", Mario Limonciello
---- On Sun, 24 Aug 2025 21:02:02 +0100 Antheas Kapenekakis <lkml@antheas.dev> wrote ---
> On the SteamOS kernel, Valve universally makes minimum brightness 0
> for all devices. SteamOS is (was?) meant for the Steam Deck, so
> enabling it universally is reasonable. However, it causes issues in
> certain devices. Therefore, introduce it just for the Steam Deck here.
>
> SteamOS kernel does not have a public mirror, but this replaces commit
> 806dd74bb225 ("amd/drm: override backlight min value from 12 -> 0")
> in the latest, as of this writing, SteamOS kernel (6.11.11-valve24).
> See unofficial mirror reconstructed from sources below.
>
> Link: https://gitlab.com/evlaV/linux-integration/-/commit/806dd74bb225
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> ---
> drivers/gpu/drm/drm_panel_backlight_quirks.c | 17 ++++++++++++++++-
> 1 file changed, 16 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> index 78c430b07d6a..5c24f4a86519 100644
> --- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
> +++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> @@ -73,7 +73,22 @@ static const struct drm_get_panel_backlight_quirk drm_panel_min_backlight_quirks
> .dmi_match_other.field = DMI_PRODUCT_NAME,
> .dmi_match_other.value = "ONEXPLAYER F1 EVA-02",
> .quirk = { .brightness_mask = 3, },
> - }
> + },
> + /* Steam Deck models */
> + {
> + .dmi_match.field = DMI_SYS_VENDOR,
> + .dmi_match.value = "Valve",
> + .dmi_match_other.field = DMI_PRODUCT_NAME,
> + .dmi_match_other.value = "Jupiter",
> + .quirk = { .min_brightness = 1, },
> + },
> + {
> + .dmi_match.field = DMI_SYS_VENDOR,
> + .dmi_match.value = "Valve",
> + .dmi_match_other.field = DMI_PRODUCT_NAME,
> + .dmi_match_other.value = "Galileo",
> + .quirk = { .min_brightness = 1, },
> + },
> };
>
> static bool drm_panel_min_backlight_quirk_matches(
> --
> 2.50.1
>
Reviewed-by: Robert Beckett <bob.beckett@collabora.com>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v1 4/5] drm: panel-backlight-quirks: Add brightness mask quirk
2025-08-24 20:02 ` [PATCH v1 4/5] drm: panel-backlight-quirks: Add brightness mask quirk Antheas Kapenekakis
2025-08-25 18:02 ` Mario Limonciello
@ 2025-08-26 12:28 ` Philip Müller
1 sibling, 0 replies; 20+ messages in thread
From: Philip Müller @ 2025-08-26 12:28 UTC (permalink / raw)
To: Antheas Kapenekakis, amd-gfx
Cc: dri-devel, linux-kernel, Alex Deucher, Christian König,
Mario Limonciello
On 8/24/25 22:02, Antheas Kapenekakis wrote:
> 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. Summary examples are found below.
>
> 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
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> ---
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 +++++
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 6 ++++
> drivers/gpu/drm/drm_panel_backlight_quirks.c | 29 +++++++++++++++++++
> include/drm/drm_utils.h | 1 +
> 4 files changed, 43 insertions(+)
>
> 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 4ad80ae615a2..156f2aae6828 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -3662,6 +3662,9 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
> if (panel_backlight_quirk->min_brightness)
> caps->min_input_signal =
> panel_backlight_quirk->min_brightness - 1;
> + if (panel_backlight_quirk->brightness_mask)
> + caps->brightness_mask =
> + panel_backlight_quirk->brightness_mask;
> }
> }
>
> @@ -4862,6 +4865,10 @@ static void amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm,
> brightness = convert_brightness_from_user(caps, dm->brightness[bl_idx]);
> link = (struct dc_link *)dm->backlight_link[bl_idx];
>
> + /* Apply brightness quirk */
> + if (caps->brightness_mask)
> + brightness |= caps->brightness_mask;
> +
> /* Change brightness based on AUX property */
> mutex_lock(&dm->dc_lock);
> if (dm->dc->caps.ips_support && dm->dc->ctx->dmub_srv->idle_allowed) {
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> index b937da0a4e4a..340f9b5f68eb 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> @@ -200,6 +200,12 @@ struct amdgpu_dm_backlight_caps {
> * @aux_support: Describes if the display supports AUX backlight.
> */
> bool aux_support;
> + /**
> + * @brightness_mask: After deriving brightness, or it with this mask.
> + * This is used to workaround panels that have issues with certain
> + * brightness values.
> + */
> + u32 brightness_mask;
> /**
> * @ac_level: the default brightness if booted on AC
> */
> diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> index 3d386a96e50e..78c430b07d6a 100644
> --- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
> +++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> @@ -45,6 +45,35 @@ static const struct drm_get_panel_backlight_quirk drm_panel_min_backlight_quirks
> .ident.name = "NE135A1M-NY1",
> .quirk = { .min_brightness = 1, },
> },
> + /* Have OLED Panels with brightness issue when last byte is 0/1 */
> + {
> + .dmi_match.field = DMI_SYS_VENDOR,
> + .dmi_match.value = "AYANEO",
> + .dmi_match_other.field = DMI_PRODUCT_NAME,
> + .dmi_match_other.value = "AYANEO 3",
> + .quirk = { .brightness_mask = 3, },
> + },
> + {
> + .dmi_match.field = DMI_SYS_VENDOR,
> + .dmi_match.value = "ZOTAC",
> + .dmi_match_other.field = DMI_BOARD_NAME,
> + .dmi_match_other.value = "G0A1W",
> + .quirk = { .brightness_mask = 3, },
> + },
> + {
> + .dmi_match.field = DMI_SYS_VENDOR,
> + .dmi_match.value = "ONE-NETBOOK",
> + .dmi_match_other.field = DMI_PRODUCT_NAME,
> + .dmi_match_other.value = "ONEXPLAYER F1Pro",
> + .quirk = { .brightness_mask = 3, },
> + },
> + {
> + .dmi_match.field = DMI_SYS_VENDOR,
> + .dmi_match.value = "ONE-NETBOOK",
> + .dmi_match_other.field = DMI_PRODUCT_NAME,
> + .dmi_match_other.value = "ONEXPLAYER F1 EVA-02",
> + .quirk = { .brightness_mask = 3, },
> + }
> };
>
> static bool drm_panel_min_backlight_quirk_matches(
> diff --git a/include/drm/drm_utils.h b/include/drm/drm_utils.h
> index 82eeee4a58ab..6a46f755daba 100644
> --- a/include/drm/drm_utils.h
> +++ b/include/drm/drm_utils.h
> @@ -18,6 +18,7 @@ int drm_get_panel_orientation_quirk(int width, int height);
>
> struct drm_panel_backlight_quirk {
> u16 min_brightness;
> + u32 brightness_mask;
> };
>
> const struct drm_panel_backlight_quirk *
Tested-by: Philip Müller <philm@manjaro.org>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v1 2/5] drm: panel-backlight-quirks: Convert brightness quirk to generic structure
2025-08-24 20:01 ` [PATCH v1 2/5] drm: panel-backlight-quirks: Convert brightness quirk to generic structure Antheas Kapenekakis
2025-08-25 17:53 ` Mario Limonciello
@ 2025-08-26 12:29 ` Philip Müller
1 sibling, 0 replies; 20+ messages in thread
From: Philip Müller @ 2025-08-26 12:29 UTC (permalink / raw)
To: Antheas Kapenekakis, amd-gfx
Cc: dri-devel, linux-kernel, Alex Deucher, Christian König,
Mario Limonciello
On 8/24/25 22:01, Antheas Kapenekakis wrote:
> Currently, the brightness quirk is limited to minimum brightness only.
> Refactor it to a structure, so that more quirks can be added in the
> future. Reserve 0 value for "no quirk", and use u16 to allow minimum
> brightness up to 255.
>
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> ---
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 12 ++++--
> .../link/protocols/link_edp_panel_control.c | 2 +-
> drivers/gpu/drm/drm_panel_backlight_quirks.c | 41 ++++++++++---------
> include/drm/drm_utils.h | 7 +++-
> 4 files changed, 36 insertions(+), 26 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..4ad80ae615a2 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -3612,11 +3612,11 @@ static struct drm_mode_config_helper_funcs amdgpu_dm_mode_config_helperfuncs = {
>
> static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
> {
> + const struct drm_panel_backlight_quirk *panel_backlight_quirk;
> struct amdgpu_dm_backlight_caps *caps;
> struct drm_connector *conn_base;
> struct amdgpu_device *adev;
> struct drm_luminance_range_info *luminance_range;
> - int min_input_signal_override;
>
> if (aconnector->bl_idx == -1 ||
> aconnector->dc_link->connector_signal != SIGNAL_TYPE_EDP)
> @@ -3656,9 +3656,13 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
> else
> caps->aux_min_input_signal = 1;
>
> - min_input_signal_override = drm_get_panel_min_brightness_quirk(aconnector->drm_edid);
> - if (min_input_signal_override >= 0)
> - caps->min_input_signal = min_input_signal_override;
> + panel_backlight_quirk =
> + drm_get_panel_backlight_quirk(aconnector->drm_edid);
> + if (!IS_ERR_OR_NULL(panel_backlight_quirk)) {
> + if (panel_backlight_quirk->min_brightness)
> + caps->min_input_signal =
> + panel_backlight_quirk->min_brightness - 1;
> + }
> }
>
> DEFINE_FREE(sink_release, struct dc_sink *, if (_T) dc_sink_release(_T))
> diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
> index e7927b8f5ba3..a1f37267b85e 100644
> --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
> +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
> @@ -201,7 +201,7 @@ bool edp_set_backlight_level_nits(struct dc_link *link,
> return false;
> } else if (link->backlight_control_type == BACKLIGHT_CONTROL_AMD_AUX) {
> struct dpcd_source_backlight_set dpcd_backlight_set;
> - *(uint32_t *)&dpcd_backlight_set.backlight_level_millinits = backlight_millinits;
> + *(uint32_t *)&dpcd_backlight_set.backlight_level_millinits = backlight_millinits | 3;
> *(uint16_t *)&dpcd_backlight_set.backlight_transition_time_ms = (uint16_t)transition_time_in_ms;
>
> uint8_t backlight_control = isHDR ? 1 : 0;
> diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> index b38b33e26ea5..702726c20ccc 100644
> --- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
> +++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> @@ -8,23 +8,23 @@
> #include <drm/drm_edid.h>
> #include <drm/drm_utils.h>
>
> -struct drm_panel_min_backlight_quirk {
> +struct drm_get_panel_backlight_quirk {
> struct {
> enum dmi_field field;
> const char * const value;
> } dmi_match;
> struct drm_edid_ident ident;
> - u8 min_brightness;
> + struct drm_panel_backlight_quirk quirk;
> };
>
> -static const struct drm_panel_min_backlight_quirk drm_panel_min_backlight_quirks[] = {
> +static const struct drm_get_panel_backlight_quirk drm_panel_min_backlight_quirks[] = {
> /* 13 inch matte panel */
> {
> .dmi_match.field = DMI_BOARD_VENDOR,
> .dmi_match.value = "Framework",
> .ident.panel_id = drm_edid_encode_panel_id('B', 'O', 'E', 0x0bca),
> .ident.name = "NE135FBM-N41",
> - .min_brightness = 0,
> + .quirk = { .min_brightness = 1, },
> },
> /* 13 inch glossy panel */
> {
> @@ -32,7 +32,7 @@ static const struct drm_panel_min_backlight_quirk drm_panel_min_backlight_quirks
> .dmi_match.value = "Framework",
> .ident.panel_id = drm_edid_encode_panel_id('B', 'O', 'E', 0x095f),
> .ident.name = "NE135FBM-N41",
> - .min_brightness = 0,
> + .quirk = { .min_brightness = 1, },
> },
> /* 13 inch 2.8k panel */
> {
> @@ -40,12 +40,13 @@ static const struct drm_panel_min_backlight_quirk drm_panel_min_backlight_quirks
> .dmi_match.value = "Framework",
> .ident.panel_id = drm_edid_encode_panel_id('B', 'O', 'E', 0x0cb4),
> .ident.name = "NE135A1M-NY1",
> - .min_brightness = 0,
> + .quirk = { .min_brightness = 1, },
> },
> };
>
> -static bool drm_panel_min_backlight_quirk_matches(const struct drm_panel_min_backlight_quirk *quirk,
> - const struct drm_edid *edid)
> +static bool drm_panel_min_backlight_quirk_matches(
> + const struct drm_get_panel_backlight_quirk *quirk,
> + const struct drm_edid *edid)
> {
> if (!dmi_match(quirk->dmi_match.field, quirk->dmi_match.value))
> return false;
> @@ -57,39 +58,39 @@ static bool drm_panel_min_backlight_quirk_matches(const struct drm_panel_min_bac
> }
>
> /**
> - * drm_get_panel_min_brightness_quirk - Get minimum supported brightness level for a panel.
> + * drm_get_panel_backlight_quirk - Get backlight quirks for a panel
> * @edid: EDID of the panel to check
> *
> * This function checks for platform specific (e.g. DMI based) quirks
> * providing info on the minimum backlight brightness for systems where this
> - * cannot be probed correctly from the hard-/firm-ware.
> + * cannot be probed correctly from the hard-/firm-ware and other sources.
> *
> * Returns:
> - * A negative error value or
> - * an override value in the range [0, 255] representing 0-100% to be scaled to
> - * the drivers target range.
> + * a drm_panel_backlight_quirk struct if a quirk was found, otherwise an
> + * error pointer.
> */
> -int drm_get_panel_min_brightness_quirk(const struct drm_edid *edid)
> +const struct drm_panel_backlight_quirk *
> +drm_get_panel_backlight_quirk(const struct drm_edid *edid)
> {
> - const struct drm_panel_min_backlight_quirk *quirk;
> + const struct drm_get_panel_backlight_quirk *quirk;
> size_t i;
>
> if (!IS_ENABLED(CONFIG_DMI))
> - return -ENODATA;
> + return ERR_PTR(-ENODATA);
>
> if (!edid)
> - return -EINVAL;
> + return ERR_PTR(-EINVAL);
>
> for (i = 0; i < ARRAY_SIZE(drm_panel_min_backlight_quirks); i++) {
> quirk = &drm_panel_min_backlight_quirks[i];
>
> if (drm_panel_min_backlight_quirk_matches(quirk, edid))
> - return quirk->min_brightness;
> + return &quirk->quirk;
> }
>
> - return -ENODATA;
> + return ERR_PTR(-ENODATA);
> }
> -EXPORT_SYMBOL(drm_get_panel_min_brightness_quirk);
> +EXPORT_SYMBOL(drm_get_panel_backlight_quirk);
>
> MODULE_DESCRIPTION("Quirks for panel backlight overrides");
> MODULE_LICENSE("GPL");
> diff --git a/include/drm/drm_utils.h b/include/drm/drm_utils.h
> index 15fa9b6865f4..82eeee4a58ab 100644
> --- a/include/drm/drm_utils.h
> +++ b/include/drm/drm_utils.h
> @@ -16,7 +16,12 @@ struct drm_edid;
>
> int drm_get_panel_orientation_quirk(int width, int height);
>
> -int drm_get_panel_min_brightness_quirk(const struct drm_edid *edid);
> +struct drm_panel_backlight_quirk {
> + u16 min_brightness;
> +};
> +
> +const struct drm_panel_backlight_quirk *
> +drm_get_panel_backlight_quirk(const struct drm_edid *edid);
>
> signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec);
>
Tested-by: Philip Müller <philm@manjaro.org>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v1 3/5] drm: panel-backlight-quirks: Add secondary DMI match
2025-08-24 20:02 ` [PATCH v1 3/5] drm: panel-backlight-quirks: Add secondary DMI match Antheas Kapenekakis
@ 2025-08-26 12:29 ` Philip Müller
0 siblings, 0 replies; 20+ messages in thread
From: Philip Müller @ 2025-08-26 12:29 UTC (permalink / raw)
To: Antheas Kapenekakis, amd-gfx
Cc: dri-devel, linux-kernel, Alex Deucher, Christian König,
Mario Limonciello
On 8/24/25 22:02, Antheas Kapenekakis wrote:
> Using a single DMI match only allows matching per manufacturer.
> Introduce a second optional match to allow matching make/model.
> In addition, make DMI optional to allow matching only by EDID.
>
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> ---
> drivers/gpu/drm/drm_panel_backlight_quirks.c | 19 ++++++++++++++-----
> 1 file changed, 14 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> index 702726c20ccc..3d386a96e50e 100644
> --- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
> +++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
> @@ -8,11 +8,14 @@
> #include <drm/drm_edid.h>
> #include <drm/drm_utils.h>
>
> +struct drm_panel_match {
> + enum dmi_field field;
> + const char * const value;
> +};
> +
> struct drm_get_panel_backlight_quirk {
> - struct {
> - enum dmi_field field;
> - const char * const value;
> - } dmi_match;
> + struct drm_panel_match dmi_match;
> + struct drm_panel_match dmi_match_other;
> struct drm_edid_ident ident;
> struct drm_panel_backlight_quirk quirk;
> };
> @@ -48,7 +51,13 @@ static bool drm_panel_min_backlight_quirk_matches(
> const struct drm_get_panel_backlight_quirk *quirk,
> const struct drm_edid *edid)
> {
> - if (!dmi_match(quirk->dmi_match.field, quirk->dmi_match.value))
> + if (quirk->dmi_match.field &&
> + !dmi_match(quirk->dmi_match.field, quirk->dmi_match.value))
> + return false;
> +
> + if (quirk->dmi_match_other.field &&
> + !dmi_match(quirk->dmi_match_other.field,
> + quirk->dmi_match_other.value))
> return false;
>
> if (quirk->ident.panel_id && !drm_edid_match(edid, &quirk->ident))
Tested-by: Philip Müller <philm@manjaro.org>
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2025-08-26 12:29 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-24 20:01 [PATCH v1 0/5] drm: panel-backlight-quirks: Do partial refactor and apply OLED fix Antheas Kapenekakis
2025-08-24 20:01 ` [PATCH v1 1/5] drm: panel-backlight-quirks: Make ident optional Antheas Kapenekakis
2025-08-24 20:01 ` [PATCH v1 2/5] drm: panel-backlight-quirks: Convert brightness quirk to generic structure Antheas Kapenekakis
2025-08-25 17:53 ` Mario Limonciello
2025-08-26 12:29 ` Philip Müller
2025-08-24 20:02 ` [PATCH v1 3/5] drm: panel-backlight-quirks: Add secondary DMI match Antheas Kapenekakis
2025-08-26 12:29 ` Philip Müller
2025-08-24 20:02 ` [PATCH v1 4/5] drm: panel-backlight-quirks: Add brightness mask quirk Antheas Kapenekakis
2025-08-25 18:02 ` Mario Limonciello
2025-08-25 21:17 ` Antheas Kapenekakis
2025-08-25 21:22 ` Mario Limonciello
2025-08-25 21:26 ` Antheas Kapenekakis
2025-08-26 12:28 ` Philip Müller
2025-08-24 20:02 ` [PATCH v1 5/5] drm: panel-backlight-quirks: Add Steam Decks Antheas Kapenekakis
2025-08-25 16:47 ` Mario Limonciello
2025-08-25 21:02 ` Antheas Kapenekakis
2025-08-25 21:05 ` Mario Limonciello
2025-08-25 21:20 ` Antheas Kapenekakis
2025-08-26 11:38 ` Robert Beckett
2025-08-25 16:45 ` [PATCH v1 0/5] drm: panel-backlight-quirks: Do partial refactor and apply OLED fix Mario Limonciello
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).