dri-devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/3] sysfb: Fix display output on Lenovo D330 (and others)
@ 2026-09-01  8:17 Thomas Zimmermann
  2026-09-01  8:17 ` [PATCH v3 1/3] firmware/sysfb: Remove rotation quirk for Lenovo D330 Thomas Zimmermann
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Thomas Zimmermann @ 2026-09-01  8:17 UTC (permalink / raw)
  To: javierm, ardb, ilias.apalodimas, jani.nikula, maarten.lankhorst,
	mripard, simona, airlied
  Cc: dri-devel, linux-efi, sashiko-reviews, Thomas Zimmermann

The kernel mis-interprets the display geometry given by the Lenovo
D330 as incorrect. The values are correct, but the display output is
rotated by 90°. With the kernel's firmware quirk applied, the output
is garbled.

Remove the firmware quirk for the Lenovo D330 and let DRM's sysfb
drivers set the correct panel orientation instead. To make this work
for any display mode, use the panel size for looking up the correct
orientation.

Tested on a Lenovo D330-10IGM IdeaPad.

v3:
- rename EDID helper to drm_edid_detect_panel_size()
- clean up EDID code (Jani)
- mention possible dependency on device firmware version
v2:
- reorder patches to have the immediate fix first
- detect and handle broken EDID better (Sashiko)
- fix width/height pointer check (Sashiko)

Thomas Zimmermann (3):
  firmware/sysfb: Remove rotation quirk for Lenovo D330
  drm/edid: Add drm_edid_detect_panel_size()
  drm/sysfb: Use preferred panel size for panel orientation quirks

 drivers/firmware/efi/sysfb_efi.c |  9 ------
 drivers/gpu/drm/drm_edid.c       | 47 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/sysfb/efidrm.c   | 17 +++++++++++-
 drivers/gpu/drm/sysfb/ofdrm.c    | 18 ++++++++++--
 drivers/gpu/drm/sysfb/vesadrm.c  | 17 +++++++++++-
 include/drm/drm_edid.h           |  2 ++
 6 files changed, 97 insertions(+), 13 deletions(-)


base-commit: aa389a514292b196ae89c6515568b3329abeec63
-- 
2.55.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v3 1/3] firmware/sysfb: Remove rotation quirk for Lenovo D330
  2026-09-01  8:17 [PATCH v3 0/3] sysfb: Fix display output on Lenovo D330 (and others) Thomas Zimmermann
@ 2026-09-01  8:17 ` Thomas Zimmermann
  2026-09-01  8:32   ` sashiko-bot
  2026-09-01  8:17 ` [PATCH v3 2/3] drm/edid: Add drm_edid_detect_panel_size() Thomas Zimmermann
  2026-09-01  8:17 ` [PATCH v3 3/3] drm/sysfb: Use preferred panel size for panel orientation quirks Thomas Zimmermann
  2 siblings, 1 reply; 7+ messages in thread
From: Thomas Zimmermann @ 2026-09-01  8:17 UTC (permalink / raw)
  To: javierm, ardb, ilias.apalodimas, jani.nikula, maarten.lankhorst,
	mripard, simona, airlied
  Cc: dri-devel, linux-efi, sashiko-reviews, Thomas Zimmermann

The Lenovo D330 is a notebook with detachable display. The display
is installed in landscape orientation, but the display mode is in
portrait orientation. By default, the display output is rotated to
the left by 90°.

The sysfb quirk breaks the display by swapping display width and
height; and thus mixing up the display geometry. Fix this by keeping
the display as-is. The sysfb DRM drivers, usually efidrm, will pick
the correct panel orientation for the display.

The exact behavior might depend on the version of the BIOS release,
but the exact version numbers of broken and good releases are unknown.
Users are advised to update to the latest firmware.

Tested on a Lenovo D330-10IGM IdeaPad with firmware 8NCN43WW.

v3:
- mention possible dependency on BIOS release in commit description

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
---
 drivers/firmware/efi/sysfb_efi.c | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/drivers/firmware/efi/sysfb_efi.c b/drivers/firmware/efi/sysfb_efi.c
index 685283bb7327..2338de73c62c 100644
--- a/drivers/firmware/efi/sysfb_efi.c
+++ b/drivers/firmware/efi/sysfb_efi.c
@@ -301,15 +301,6 @@ static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = {
 		},
 		.callback = efifb_swap_width_height,
 	},
-	{
-		/* Lenovo D330 with 800x1280 or 1200x1920 portrait screen */
-		.matches = {
-			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-			DMI_EXACT_MATCH(DMI_PRODUCT_VERSION,
-					"Lenovo ideapad D330-10IGM"),
-		},
-		.callback = efifb_swap_width_height,
-	},
 	{
 		/*
 		 * Lenovo IdeaPad Duet 3 10IGL5 and 10IGL5-LTE with
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v3 2/3] drm/edid: Add drm_edid_detect_panel_size()
  2026-09-01  8:17 [PATCH v3 0/3] sysfb: Fix display output on Lenovo D330 (and others) Thomas Zimmermann
  2026-09-01  8:17 ` [PATCH v3 1/3] firmware/sysfb: Remove rotation quirk for Lenovo D330 Thomas Zimmermann
@ 2026-09-01  8:17 ` Thomas Zimmermann
  2026-09-02  8:45   ` Jani Nikula
  2026-09-01  8:17 ` [PATCH v3 3/3] drm/sysfb: Use preferred panel size for panel orientation quirks Thomas Zimmermann
  2 siblings, 1 reply; 7+ messages in thread
From: Thomas Zimmermann @ 2026-09-01  8:17 UTC (permalink / raw)
  To: javierm, ardb, ilias.apalodimas, jani.nikula, maarten.lankhorst,
	mripard, simona, airlied
  Cc: dri-devel, linux-efi, sashiko-reviews, Thomas Zimmermann

Add drm_edid_detect_panel_size() to extract the panel's preferred
display resolution from a given EDID. Required for setting up DRM's
panel orientation quirks in sysfb drivers.

v3:
- mention use case in documentation (Jani)
- use is_detailed_timing_descriptor() (Jani)
- rename helper to drm_edid_detect_panel_size()
v2:
- handle EDID without pixel timing descriptor (Sashiko)
- fix checks for width and height pointers

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
---
 drivers/gpu/drm/drm_edid.c | 47 ++++++++++++++++++++++++++++++++++++++
 include/drm/drm_edid.h     |  2 ++
 2 files changed, 49 insertions(+)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 9990a836d0b6..d5d9e77dc91b 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -7852,3 +7852,50 @@ bool drm_edid_is_digital(const struct drm_edid *drm_edid)
 		drm_edid->edid->input & DRM_EDID_INPUT_DIGITAL;
 }
 EXPORT_SYMBOL(drm_edid_is_digital);
+
+/**
+ * drm_edid_detect_panel_size - Get a panel's size from EDID
+ * @drm_edid: EDID of the panel.
+ * @width: Returns the panel's width in pixels per scanline, if given
+ * @height: Returns the panel's height in scanlines, if given
+ *
+ * This function detects the preferred size of a panel from the given
+ * EDID. There is no such information stored in the EDID block directly,
+ * but the preferred mode often corresponds to the panel's native geometry.
+ *
+ * This helper should only be used during initialization before the
+ * connector is available. For regular use, retrieve the available display
+ * modes with the connector functions.
+ *
+ * Return: Zero on success, or a negative errno code otherwise.
+ */
+int drm_edid_detect_panel_size(const struct drm_edid *drm_edid,
+			       unsigned int *width, unsigned int *height)
+{
+	const struct edid *edid = drm_edid->edid;
+	const struct detailed_timing *dt;
+	const struct detailed_pixel_timing *pt;
+
+	/*
+	 * Use display mode from the Preferred Timing Descriptor. For old
+	 * and obscure displays, we might need better heuristics.
+	 */
+
+	if (edid->revision < 4 && !(edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING))
+		return -EINVAL; /* no Preferred Timing Descriptor */
+
+	dt = &edid->detailed_timings[0];
+
+	if (!is_detailed_timing_descriptor(dt))
+		return -EINVAL;
+
+	pt = &dt->data.pixel_data;
+
+	if (width)
+		*width = (pt->hactive_hblank_hi & 0xf0) << 4 | pt->hactive_lo;
+	if (height)
+		*height = (pt->vactive_vblank_hi & 0xf0) << 4 | pt->vactive_lo;
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_edid_detect_panel_size);
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 04f7a7f1f108..a2617aa34edf 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -490,5 +490,7 @@ u32 drm_edid_get_panel_id(const struct drm_edid *drm_edid);
 bool drm_edid_match(const struct drm_edid *drm_edid,
 		    const struct drm_edid_ident *ident);
 bool drm_edid_has_quirk(struct drm_connector *connector, enum drm_edid_quirk quirk);
+int drm_edid_detect_panel_size(const struct drm_edid *drm_edid,
+			       unsigned int *width, unsigned int *height);
 
 #endif /* __DRM_EDID_H__ */
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v3 3/3] drm/sysfb: Use preferred panel size for panel orientation quirks
  2026-09-01  8:17 [PATCH v3 0/3] sysfb: Fix display output on Lenovo D330 (and others) Thomas Zimmermann
  2026-09-01  8:17 ` [PATCH v3 1/3] firmware/sysfb: Remove rotation quirk for Lenovo D330 Thomas Zimmermann
  2026-09-01  8:17 ` [PATCH v3 2/3] drm/edid: Add drm_edid_detect_panel_size() Thomas Zimmermann
@ 2026-09-01  8:17 ` Thomas Zimmermann
  2 siblings, 0 replies; 7+ messages in thread
From: Thomas Zimmermann @ 2026-09-01  8:17 UTC (permalink / raw)
  To: javierm, ardb, ilias.apalodimas, jani.nikula, maarten.lankhorst,
	mripard, simona, airlied
  Cc: dri-devel, linux-efi, sashiko-reviews, Thomas Zimmermann

Sysfb drivers currently use the given display mode for looking up the
panel orientation. But the look-up table stores the native geometry of
the panels, so the lookup fails if the current mode sizes differs.

Get the panel's native geometry with drm_edid_detect_panel_size() from
the EDID and use it for looking up the panel orientation.

v2:
- ofdrm: validate EDID header before using it (Sashiko)

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
---
 drivers/gpu/drm/sysfb/efidrm.c  | 17 ++++++++++++++++-
 drivers/gpu/drm/sysfb/ofdrm.c   | 18 ++++++++++++++++--
 drivers/gpu/drm/sysfb/vesadrm.c | 17 ++++++++++++++++-
 3 files changed, 48 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/sysfb/efidrm.c b/drivers/gpu/drm/sysfb/efidrm.c
index 3f9cd5d03efb..8b19f437308e 100644
--- a/drivers/gpu/drm/sysfb/efidrm.c
+++ b/drivers/gpu/drm/sysfb/efidrm.c
@@ -152,6 +152,7 @@ static struct efidrm_device *efidrm_device_create(struct drm_driver *drv,
 	const struct screen_info *si;
 	const struct drm_format_info *format;
 	int width, height, stride;
+	unsigned int panel_width, panel_height;
 	s64 vsize;
 	u64 mem_flags;
 	struct resource resbuf;
@@ -217,6 +218,20 @@ static struct efidrm_device *efidrm_device_create(struct drm_driver *drv,
 	if (drm_edid_header_is_valid(dpy->edid.dummy) == 8)
 		sysfb->edid = dpy->edid.dummy;
 #endif
+
+	panel_width = width;
+	panel_height = height;
+
+	if (sysfb->edid) {
+		const struct drm_edid *drm_edid;
+
+		drm_edid = drm_edid_alloc(sysfb->edid, EDID_LENGTH);
+		if (drm_edid) {
+			drm_edid_detect_panel_size(drm_edid, &panel_width, &panel_height);
+			drm_edid_free(drm_edid);
+		}
+	}
+
 	sysfb->fb_mode = drm_sysfb_mode(width, height, 0, 0);
 	sysfb->fb_format = format;
 	sysfb->fb_pitch = stride;
@@ -340,7 +355,7 @@ static struct efidrm_device *efidrm_device_create(struct drm_driver *drv,
 	drm_connector_helper_add(connector, &efidrm_connector_helper_funcs);
 	drm_connector_set_panel_orientation_with_quirk(connector,
 						       DRM_MODE_PANEL_ORIENTATION_UNKNOWN,
-						       width, height);
+						       panel_width, panel_height);
 	if (sysfb->edid)
 		drm_connector_attach_edid_property(connector);
 
diff --git a/drivers/gpu/drm/sysfb/ofdrm.c b/drivers/gpu/drm/sysfb/ofdrm.c
index 9d60db45139c..c41255569854 100644
--- a/drivers/gpu/drm/sysfb/ofdrm.c
+++ b/drivers/gpu/drm/sysfb/ofdrm.c
@@ -229,7 +229,7 @@ static const u8 *display_get_edid_of(struct drm_device *dev, struct device_node
 {
 	int ret = of_property_read_u8_array(of_node, "EDID", buf, EDID_LENGTH);
 
-	if (ret)
+	if (ret || drm_edid_header_is_valid(buf) != 8)
 		return NULL;
 	return buf;
 }
@@ -828,6 +828,7 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
 	enum ofdrm_model model;
 	bool big_endian;
 	int width, height, depth, linebytes;
+	unsigned int panel_width, panel_height;
 	const struct drm_format_info *format;
 	u64 address;
 	const u8 *edid;
@@ -998,6 +999,19 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
 		sysfb->fb_gamma_lut_size = OFDRM_GAMMA_LUT_SIZE;
 	sysfb->edid = edid;
 
+	panel_width = width;
+	panel_height = height;
+
+	if (sysfb->edid) {
+		const struct drm_edid *drm_edid;
+
+		drm_edid = drm_edid_alloc(sysfb->edid, EDID_LENGTH);
+		if (drm_edid) {
+			drm_edid_detect_panel_size(drm_edid, &panel_width, &panel_height);
+			drm_edid_free(drm_edid);
+		}
+	}
+
 	drm_dbg(dev, "display mode={" DRM_MODE_FMT "}\n", DRM_MODE_ARG(&sysfb->fb_mode));
 	drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, linebytes=%d byte\n",
 		&format->format, width, height, linebytes);
@@ -1069,7 +1083,7 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
 	drm_connector_helper_add(connector, &ofdrm_connector_helper_funcs);
 	drm_connector_set_panel_orientation_with_quirk(connector,
 						       DRM_MODE_PANEL_ORIENTATION_UNKNOWN,
-						       width, height);
+						       panel_width, panel_height);
 	if (edid)
 		drm_connector_attach_edid_property(connector);
 
diff --git a/drivers/gpu/drm/sysfb/vesadrm.c b/drivers/gpu/drm/sysfb/vesadrm.c
index 6a67b2d2e451..f6358a0a68bd 100644
--- a/drivers/gpu/drm/sysfb/vesadrm.c
+++ b/drivers/gpu/drm/sysfb/vesadrm.c
@@ -402,6 +402,7 @@ static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv,
 	const struct screen_info *si;
 	const struct drm_format_info *format;
 	int width, height, stride;
+	unsigned int panel_width, panel_height;
 	s64 vsize;
 	struct resource resbuf;
 	struct resource *res;
@@ -484,6 +485,20 @@ static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv,
 	if (drm_edid_header_is_valid(dpy->edid.dummy) == 8)
 		sysfb->edid = dpy->edid.dummy;
 #endif
+
+	panel_width = width;
+	panel_height = height;
+
+	if (sysfb->edid) {
+		const struct drm_edid *drm_edid;
+
+		drm_edid = drm_edid_alloc(sysfb->edid, EDID_LENGTH);
+		if (drm_edid) {
+			drm_edid_detect_panel_size(drm_edid, &panel_width, &panel_height);
+			drm_edid_free(drm_edid);
+		}
+	}
+
 	sysfb->fb_mode = drm_sysfb_mode(width, height, 0, 0);
 	sysfb->fb_format = format;
 	sysfb->fb_pitch = stride;
@@ -585,7 +600,7 @@ static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv,
 	drm_connector_helper_add(connector, &vesadrm_connector_helper_funcs);
 	drm_connector_set_panel_orientation_with_quirk(connector,
 						       DRM_MODE_PANEL_ORIENTATION_UNKNOWN,
-						       width, height);
+						       panel_width, panel_height);
 	if (sysfb->edid)
 		drm_connector_attach_edid_property(connector);
 
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v3 1/3] firmware/sysfb: Remove rotation quirk for Lenovo D330
  2026-09-01  8:17 ` [PATCH v3 1/3] firmware/sysfb: Remove rotation quirk for Lenovo D330 Thomas Zimmermann
@ 2026-09-01  8:32   ` sashiko-bot
  0 siblings, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-09-01  8:32 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: dri-devel

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Removing the sysfb swap quirk breaks display rotation on Lenovo D330 systems with older BIOS versions.
--

commit f8f13abb4b89a4b4aa3805bfd4d2f46d356e038c
Author: Thomas Zimmermann <tzimmermann@suse.de>

firmware/sysfb: Remove rotation quirk for Lenovo D330

This commit removes the sysfb width/height swap quirk for the Lenovo D330.
It notes that the quirk breaks the display geometry on the tested firmware,
but acknowledges the behavior might depend on the BIOS release and advises
users to update their firmware to avoid issues.

> diff --git a/drivers/firmware/efi/sysfb_efi.c b/drivers/firmware/efi/sysfb_efi.c
> index 685283bb7327a..2338de73c62c9 100644
> --- a/drivers/firmware/efi/sysfb_efi.c
> +++ b/drivers/firmware/efi/sysfb_efi.c
> @@ -301,15 +301,6 @@ static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = {
>  		},
>  		.callback = efifb_swap_width_height,
>  	},
> -	{
> -		/* Lenovo D330 with 800x1280 or 1200x1920 portrait screen */
> -		.matches = {
> -			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
> -			DMI_EXACT_MATCH(DMI_PRODUCT_VERSION,
> -					"Lenovo ideapad D330-10IGM"),
> -		},
> -		.callback = efifb_swap_width_height,
> -	},

[Severity: High]
Does unconditionally removing this quirk cause a regression for users on
older BIOS versions?

If a user boots a Lenovo D330-10IGM with an older BIOS that incorrectly
reports a landscape resolution (e.g., 1280x800) for a portrait-stride
hardware setup, removing this dynamic swap leaves the dimensions uncorrected.

For drivers like simpledrm (which do not use EDID) or even efidrm (where the
framebuffer geometry is derived from the uncorrected si->lfb_width and
si->lfb_height), this will result in complete display corruption due to
mismatched strides.

Since the kernel has a strict policy against regressions, advising users to
update their firmware to fix a kernel-introduced regression might not be
sufficient.

Could this be fixed by keeping the quirk but conditionally applying the swap
inside efifb_swap_width_height() only if si->lfb_width > si->lfb_height?
This approach might fix the geometry for newer BIOS releases without breaking
the older ones.

>  	{
>  		/*
>  		 * Lenovo IdeaPad Duet 3 10IGL5 and 10IGL5-LTE with

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260901082057.37617-1-tzimmermann@suse.de?part=1

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v3 2/3] drm/edid: Add drm_edid_detect_panel_size()
  2026-09-01  8:17 ` [PATCH v3 2/3] drm/edid: Add drm_edid_detect_panel_size() Thomas Zimmermann
@ 2026-09-02  8:45   ` Jani Nikula
  2026-09-02 11:06     ` Thomas Zimmermann
  0 siblings, 1 reply; 7+ messages in thread
From: Jani Nikula @ 2026-09-02  8:45 UTC (permalink / raw)
  To: Thomas Zimmermann, javierm, ardb, ilias.apalodimas,
	maarten.lankhorst, mripard, simona, airlied
  Cc: dri-devel, linux-efi, sashiko-reviews, Thomas Zimmermann

On Tue, 01 Sep 2026, Thomas Zimmermann <tzimmermann@suse.de> wrote:
> Add drm_edid_detect_panel_size() to extract the panel's preferred
> display resolution from a given EDID. Required for setting up DRM's
> panel orientation quirks in sysfb drivers.
>
> v3:
> - mention use case in documentation (Jani)
> - use is_detailed_timing_descriptor() (Jani)
> - rename helper to drm_edid_detect_panel_size()
> v2:
> - handle EDID without pixel timing descriptor (Sashiko)
> - fix checks for width and height pointers
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Acked-by: Ard Biesheuvel <ardb@kernel.org>
> ---
>  drivers/gpu/drm/drm_edid.c | 47 ++++++++++++++++++++++++++++++++++++++
>  include/drm/drm_edid.h     |  2 ++
>  2 files changed, 49 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> index 9990a836d0b6..d5d9e77dc91b 100644
> --- a/drivers/gpu/drm/drm_edid.c
> +++ b/drivers/gpu/drm/drm_edid.c
> @@ -7852,3 +7852,50 @@ bool drm_edid_is_digital(const struct drm_edid *drm_edid)
>  		drm_edid->edid->input & DRM_EDID_INPUT_DIGITAL;
>  }
>  EXPORT_SYMBOL(drm_edid_is_digital);
> +
> +/**
> + * drm_edid_detect_panel_size - Get a panel's size from EDID
> + * @drm_edid: EDID of the panel.
> + * @width: Returns the panel's width in pixels per scanline, if given
> + * @height: Returns the panel's height in scanlines, if given
> + *
> + * This function detects the preferred size of a panel from the given
> + * EDID. There is no such information stored in the EDID block directly,
> + * but the preferred mode often corresponds to the panel's native geometry.
> + *
> + * This helper should only be used during initialization before the
> + * connector is available. For regular use, retrieve the available display
> + * modes with the connector functions.
> + *
> + * Return: Zero on success, or a negative errno code otherwise.
> + */
> +int drm_edid_detect_panel_size(const struct drm_edid *drm_edid,
> +			       unsigned int *width, unsigned int *height)
> +{
> +	const struct edid *edid = drm_edid->edid;
> +	const struct detailed_timing *dt;
> +	const struct detailed_pixel_timing *pt;
> +
> +	/*
> +	 * Use display mode from the Preferred Timing Descriptor. For old
> +	 * and obscure displays, we might need better heuristics.
> +	 */
> +
> +	if (edid->revision < 4 && !(edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING))
> +		return -EINVAL; /* no Preferred Timing Descriptor */

Okay, so I should've asked this n versions ago, but should that be
s/&&/||/ instead?

> +
> +	dt = &edid->detailed_timings[0];
> +
> +	if (!is_detailed_timing_descriptor(dt))
> +		return -EINVAL;
> +
> +	pt = &dt->data.pixel_data;
> +
> +	if (width)
> +		*width = (pt->hactive_hblank_hi & 0xf0) << 4 | pt->hactive_lo;
> +	if (height)
> +		*height = (pt->vactive_vblank_hi & 0xf0) << 4 | pt->vactive_lo;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(drm_edid_detect_panel_size);
> diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
> index 04f7a7f1f108..a2617aa34edf 100644
> --- a/include/drm/drm_edid.h
> +++ b/include/drm/drm_edid.h
> @@ -490,5 +490,7 @@ u32 drm_edid_get_panel_id(const struct drm_edid *drm_edid);
>  bool drm_edid_match(const struct drm_edid *drm_edid,
>  		    const struct drm_edid_ident *ident);
>  bool drm_edid_has_quirk(struct drm_connector *connector, enum drm_edid_quirk quirk);
> +int drm_edid_detect_panel_size(const struct drm_edid *drm_edid,
> +			       unsigned int *width, unsigned int *height);
>  
>  #endif /* __DRM_EDID_H__ */

-- 
Jani Nikula, Intel

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v3 2/3] drm/edid: Add drm_edid_detect_panel_size()
  2026-09-02  8:45   ` Jani Nikula
@ 2026-09-02 11:06     ` Thomas Zimmermann
  0 siblings, 0 replies; 7+ messages in thread
From: Thomas Zimmermann @ 2026-09-02 11:06 UTC (permalink / raw)
  To: Jani Nikula, javierm, ardb, ilias.apalodimas, maarten.lankhorst,
	mripard, simona, airlied
  Cc: dri-devel, linux-efi, sashiko-reviews

Hi

Am 02.09.26 um 10:45 schrieb Jani Nikula:
> On Tue, 01 Sep 2026, Thomas Zimmermann <tzimmermann@suse.de> wrote:
>> Add drm_edid_detect_panel_size() to extract the panel's preferred
>> display resolution from a given EDID. Required for setting up DRM's
>> panel orientation quirks in sysfb drivers.
>>
>> v3:
>> - mention use case in documentation (Jani)
>> - use is_detailed_timing_descriptor() (Jani)
>> - rename helper to drm_edid_detect_panel_size()
>> v2:
>> - handle EDID without pixel timing descriptor (Sashiko)
>> - fix checks for width and height pointers
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> Acked-by: Ard Biesheuvel <ardb@kernel.org>
>> ---
>>   drivers/gpu/drm/drm_edid.c | 47 ++++++++++++++++++++++++++++++++++++++
>>   include/drm/drm_edid.h     |  2 ++
>>   2 files changed, 49 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
>> index 9990a836d0b6..d5d9e77dc91b 100644
>> --- a/drivers/gpu/drm/drm_edid.c
>> +++ b/drivers/gpu/drm/drm_edid.c
>> @@ -7852,3 +7852,50 @@ bool drm_edid_is_digital(const struct drm_edid *drm_edid)
>>   		drm_edid->edid->input & DRM_EDID_INPUT_DIGITAL;
>>   }
>>   EXPORT_SYMBOL(drm_edid_is_digital);
>> +
>> +/**
>> + * drm_edid_detect_panel_size - Get a panel's size from EDID
>> + * @drm_edid: EDID of the panel.
>> + * @width: Returns the panel's width in pixels per scanline, if given
>> + * @height: Returns the panel's height in scanlines, if given
>> + *
>> + * This function detects the preferred size of a panel from the given
>> + * EDID. There is no such information stored in the EDID block directly,
>> + * but the preferred mode often corresponds to the panel's native geometry.
>> + *
>> + * This helper should only be used during initialization before the
>> + * connector is available. For regular use, retrieve the available display
>> + * modes with the connector functions.
>> + *
>> + * Return: Zero on success, or a negative errno code otherwise.
>> + */
>> +int drm_edid_detect_panel_size(const struct drm_edid *drm_edid,
>> +			       unsigned int *width, unsigned int *height)
>> +{
>> +	const struct edid *edid = drm_edid->edid;
>> +	const struct detailed_timing *dt;
>> +	const struct detailed_pixel_timing *pt;
>> +
>> +	/*
>> +	 * Use display mode from the Preferred Timing Descriptor. For old
>> +	 * and obscure displays, we might need better heuristics.
>> +	 */
>> +
>> +	if (edid->revision < 4 && !(edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING))
>> +		return -EINVAL; /* no Preferred Timing Descriptor */
> Okay, so I should've asked this n versions ago, but should that be
> s/&&/||/ instead?

You're right. And I could have sworn that I took this logic from 
somewhere in this file, but that doesn't seem to be the case. Apologies 
for such a stupid mistake.

Best regards
Thomas

>
>> +
>> +	dt = &edid->detailed_timings[0];
>> +
>> +	if (!is_detailed_timing_descriptor(dt))
>> +		return -EINVAL;
>> +
>> +	pt = &dt->data.pixel_data;
>> +
>> +	if (width)
>> +		*width = (pt->hactive_hblank_hi & 0xf0) << 4 | pt->hactive_lo;
>> +	if (height)
>> +		*height = (pt->vactive_vblank_hi & 0xf0) << 4 | pt->vactive_lo;
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(drm_edid_detect_panel_size);
>> diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
>> index 04f7a7f1f108..a2617aa34edf 100644
>> --- a/include/drm/drm_edid.h
>> +++ b/include/drm/drm_edid.h
>> @@ -490,5 +490,7 @@ u32 drm_edid_get_panel_id(const struct drm_edid *drm_edid);
>>   bool drm_edid_match(const struct drm_edid *drm_edid,
>>   		    const struct drm_edid_ident *ident);
>>   bool drm_edid_has_quirk(struct drm_connector *connector, enum drm_edid_quirk quirk);
>> +int drm_edid_detect_panel_size(const struct drm_edid *drm_edid,
>> +			       unsigned int *width, unsigned int *height);
>>   
>>   #endif /* __DRM_EDID_H__ */

-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com
GF: Jochen Jaser, Andrew McDonald, (HRB 36809, AG Nürnberg)



^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-09-02 11:06 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-01  8:17 [PATCH v3 0/3] sysfb: Fix display output on Lenovo D330 (and others) Thomas Zimmermann
2026-09-01  8:17 ` [PATCH v3 1/3] firmware/sysfb: Remove rotation quirk for Lenovo D330 Thomas Zimmermann
2026-09-01  8:32   ` sashiko-bot
2026-09-01  8:17 ` [PATCH v3 2/3] drm/edid: Add drm_edid_detect_panel_size() Thomas Zimmermann
2026-09-02  8:45   ` Jani Nikula
2026-09-02 11:06     ` Thomas Zimmermann
2026-09-01  8:17 ` [PATCH v3 3/3] drm/sysfb: Use preferred panel size for panel orientation quirks Thomas Zimmermann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox