]> git.hungrycats.org Git - linux/commitdiff
drm/amd/display: Fix refresh rate range for some panel
authorTom Chung <chiahsuan.chung@amd.com>
Fri, 14 Jun 2024 07:38:56 +0000 (15:38 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 25 Jul 2024 07:53:38 +0000 (09:53 +0200)
[ Upstream commit 9ef1548aeaa8858e7aee2152bf95cc71cdcd6dff ]

[Why]
Some of the panels does not have the refresh rate range info
in base EDID and only have the refresh rate range info in
DisplayID block.
It will cause the max/min freesync refresh rate set to 0.

[How]
Try to parse the refresh rate range info from DisplayID if the
max/min refresh rate is 0.

Reviewed-by: Sun peng Li <sunpeng.li@amd.com>
Signed-off-by: Jerry Zuo <jerry.zuo@amd.com>
Signed-off-by: Tom Chung <chiahsuan.chung@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c

index 087d7aad8e6b4b34bcf8cb1fdb19c36ca5221eb7..c29d271579ad365c71f10a7a6e3899b5731fd293 100644 (file)
@@ -11161,6 +11161,49 @@ static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector,
        return ret;
 }
 
+static void parse_edid_displayid_vrr(struct drm_connector *connector,
+               struct edid *edid)
+{
+       u8 *edid_ext = NULL;
+       int i;
+       int j = 0;
+       u16 min_vfreq;
+       u16 max_vfreq;
+
+       if (edid == NULL || edid->extensions == 0)
+               return;
+
+       /* Find DisplayID extension */
+       for (i = 0; i < edid->extensions; i++) {
+               edid_ext = (void *)(edid + (i + 1));
+               if (edid_ext[0] == DISPLAYID_EXT)
+                       break;
+       }
+
+       if (edid_ext == NULL)
+               return;
+
+       while (j < EDID_LENGTH) {
+               /* Get dynamic video timing range from DisplayID if available */
+               if (EDID_LENGTH - j > 13 && edid_ext[j] == 0x25 &&
+                   (edid_ext[j+1] & 0xFE) == 0 && (edid_ext[j+2] == 9)) {
+                       min_vfreq = edid_ext[j+9];
+                       if (edid_ext[j+1] & 7)
+                               max_vfreq = edid_ext[j+10] + ((edid_ext[j+11] & 3) << 8);
+                       else
+                               max_vfreq = edid_ext[j+10];
+
+                       if (max_vfreq && min_vfreq) {
+                               connector->display_info.monitor_range.max_vfreq = max_vfreq;
+                               connector->display_info.monitor_range.min_vfreq = min_vfreq;
+
+                               return;
+                       }
+               }
+               j++;
+       }
+}
+
 static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector,
                          struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info)
 {
@@ -11282,6 +11325,11 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
        if (!adev->dm.freesync_module)
                goto update;
 
+       /* Some eDP panels only have the refresh rate range info in DisplayID */
+       if ((connector->display_info.monitor_range.min_vfreq == 0 ||
+            connector->display_info.monitor_range.max_vfreq == 0))
+               parse_edid_displayid_vrr(connector, edid);
+
        if (edid && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
                     sink->sink_signal == SIGNAL_TYPE_EDP)) {
                bool edid_check_required = false;