]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
drm/edid: Handle EDID 1.4 range descriptor h/vfreq offsets
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Fri, 26 Aug 2022 21:34:51 +0000 (00:34 +0300)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Fri, 2 Sep 2022 13:38:51 +0000 (16:38 +0300)
EDID 1.4 introduced some extra flags in the range
descriptor to support min/max h/vfreq >= 255. Consult them
to correctly parse the vfreq limits.

Note that some combinations of the flags are documented
as "reserved" (as are some other values in the descriptor)
but explicitly checking for those doesn't seem particularly
worthwile since we end up with bogus results whether we
decode them or not.

v2: Increase the storage to u16 to make it work (Jani)
    Note the "reserved" values situation (Jani)
v3: Document the EDID version number in the defines
    Drop some bogus (u8) casts

Cc: stable@vger.kernel.org
Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/6519
References: https://gitlab.freedesktop.org/drm/intel/-/issues/6484
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220826213501.31490-2-ville.syrjala@linux.intel.com
Reviewed-by: Manasi Navare <manasi.d.navare@intel.com>
drivers/gpu/drm/drm_debugfs.c
drivers/gpu/drm/drm_edid.c
include/drm/drm_connector.h
include/drm/drm_edid.h

index 493922069c9041194a0d9ab3519f92e9e2fd4e85..01ee3febb81315d1afbbc172c94d2d56b337b559 100644 (file)
@@ -377,8 +377,8 @@ static int vrr_range_show(struct seq_file *m, void *data)
        if (connector->status != connector_status_connected)
                return -ENODEV;
 
-       seq_printf(m, "Min: %u\n", (u8)connector->display_info.monitor_range.min_vfreq);
-       seq_printf(m, "Max: %u\n", (u8)connector->display_info.monitor_range.max_vfreq);
+       seq_printf(m, "Min: %u\n", connector->display_info.monitor_range.min_vfreq);
+       seq_printf(m, "Max: %u\n", connector->display_info.monitor_range.max_vfreq);
 
        return 0;
 }
index bbc25e3b7220a2ffe68b8288d2af56279b1ae208..eaa819381281be2f41f47e1c717cc79322e3db04 100644 (file)
@@ -5971,12 +5971,14 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
 }
 
 static
-void get_monitor_range(const struct detailed_timing *timing,
-                      void *info_monitor_range)
+void get_monitor_range(const struct detailed_timing *timing, void *c)
 {
-       struct drm_monitor_range_info *monitor_range = info_monitor_range;
+       struct detailed_mode_closure *closure = c;
+       struct drm_display_info *info = &closure->connector->display_info;
+       struct drm_monitor_range_info *monitor_range = &info->monitor_range;
        const struct detailed_non_pixel *data = &timing->data.other_data;
        const struct detailed_data_monitor_range *range = &data->data.range;
+       const struct edid *edid = closure->drm_edid->edid;
 
        if (!is_display_descriptor(timing, EDID_DETAIL_MONITOR_RANGE))
                return;
@@ -5992,18 +5994,28 @@ void get_monitor_range(const struct detailed_timing *timing,
 
        monitor_range->min_vfreq = range->min_vfreq;
        monitor_range->max_vfreq = range->max_vfreq;
+
+       if (edid->revision >= 4) {
+               if (data->pad2 & DRM_EDID_RANGE_OFFSET_MIN_VFREQ)
+                       monitor_range->min_vfreq += 255;
+               if (data->pad2 & DRM_EDID_RANGE_OFFSET_MAX_VFREQ)
+                       monitor_range->max_vfreq += 255;
+       }
 }
 
 static void drm_get_monitor_range(struct drm_connector *connector,
                                  const struct drm_edid *drm_edid)
 {
-       struct drm_display_info *info = &connector->display_info;
+       const struct drm_display_info *info = &connector->display_info;
+       struct detailed_mode_closure closure = {
+               .connector = connector,
+               .drm_edid = drm_edid,
+       };
 
        if (!version_greater(drm_edid, 1, 1))
                return;
 
-       drm_for_each_detailed_block(drm_edid, get_monitor_range,
-                                   &info->monitor_range);
+       drm_for_each_detailed_block(drm_edid, get_monitor_range, &closure);
 
        DRM_DEBUG_KMS("Supported Monitor Refresh rate range is %d Hz - %d Hz\n",
                      info->monitor_range.min_vfreq,
index a1705d6b3fba20d9be64a651b9f2f3cb4a5c36e8..7df7876b2ad5634fe373d2ef6aabe245a57ab26d 100644 (file)
@@ -319,8 +319,8 @@ enum drm_panel_orientation {
  *             EDID's detailed monitor range
  */
 struct drm_monitor_range_info {
-       u8 min_vfreq;
-       u8 max_vfreq;
+       u16 min_vfreq;
+       u16 max_vfreq;
 };
 
 /**
index 2181977ae6839c6caedb0957c43306dcf4e8da35..1ed61e2b30a41c70b40682f01bd011d4047a886a 100644 (file)
@@ -92,6 +92,11 @@ struct detailed_data_string {
        u8 str[13];
 } __attribute__((packed));
 
+#define DRM_EDID_RANGE_OFFSET_MIN_VFREQ (1 << 0) /* 1.4 */
+#define DRM_EDID_RANGE_OFFSET_MAX_VFREQ (1 << 1) /* 1.4 */
+#define DRM_EDID_RANGE_OFFSET_MIN_HFREQ (1 << 2) /* 1.4 */
+#define DRM_EDID_RANGE_OFFSET_MAX_HFREQ (1 << 3) /* 1.4 */
+
 #define DRM_EDID_DEFAULT_GTF_SUPPORT_FLAG   0x00
 #define DRM_EDID_RANGE_LIMITS_ONLY_FLAG     0x01
 #define DRM_EDID_SECONDARY_GTF_SUPPORT_FLAG 0x02