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 <[email protected]>
Acked-by: Ard Biesheuvel <[email protected]>
---
 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

Reply via email to