From: Fangzhi Zuo <[email protected]>

[why]
Some panels advertise a FreeSync range minimum that does not operate
reliably at the low end:
- X34GS (EDID panel id ACR 0x08AF) reports a minimum that
  can flicker or drop out when the refresh rate approaches the reported
  minimum.
- 34w-30 (EDID panel id LEN 0x66F1) reports a 48 Hz minimum over
  DisplayPort, but the panel fails to light up at that minimum, resulting
  in a black screen. Forcing the minimum to 60 Hz avoids the black screen
  and lets the display light up normally.

[how]
- Add a force_freesync_min_hz field to struct dc_panel_patch.
- Add apply_edid_quirks() cases keyed on the affected panel ids that set
  force_freesync_min_hz (55 Hz for the X34GS, 60 Hz for the G34w-30).
- In amdgpu_dm_update_freesync_caps(), when the quirk is set and the sink
  is otherwise FreeSync capable, clamp the reported VRR range minimum
  (min_vfreq and monitor_range.min_vfreq) to the quirked value.
- Add a KUnit test covering the new quirk.

Reviewed-by: George Zhang <[email protected]>
Signed-off-by: Fangzhi Zuo <[email protected]>
Signed-off-by: Tom Chung <[email protected]>
---
 .../display/amdgpu_dm/amdgpu_dm_connector.c    | 12 ++++++++++++
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c  | 18 ++++++++++++++++++
 .../amdgpu_dm/tests/amdgpu_dm_helpers_test.c   | 17 +++++++++++++++++
 drivers/gpu/drm/amd/display/dc/dc_types.h      |  1 +
 4 files changed, 48 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 4304520d2484..2cc3734c992b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -3880,6 +3880,18 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector 
*connector,
                }
        }
 
+       /*
+        * Apply per-monitor FreeSync range quirks. Some panels report a
+        * VRR minimum that does not operate reliably; force it when the
+        * monitor is quirked (see apply_edid_quirks()).
+        */
+       if (sink->edid_caps.panel_patch.force_freesync_min_hz && 
freesync_capable) {
+               amdgpu_dm_connector->min_vfreq =
+                       sink->edid_caps.panel_patch.force_freesync_min_hz;
+               connector->display_info.monitor_range.min_vfreq =
+                       amdgpu_dm_connector->min_vfreq;
+       }
+
        /* Handle MCCS */
        if (do_mccs)
                dm_helpers_read_mccs_caps(adev->dm.dc->ctx, 
amdgpu_dm_connector->dc_link, sink);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index d451082552e8..b05455498cbf 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -147,6 +147,24 @@ STATIC_IFN_KUNIT void apply_edid_quirks(struct dc_link 
*link, struct edid *edid,
                drm_dbg_driver(dev, "Hiding secondary tile on panel id %X\n", 
panel_id);
                edid_caps->panel_patch.disable_second_tile = true;
                break;
+       /*
+        * Workaround for the Acer Predator X34GS which reports a FreeSync
+        * minimum refresh rate that does not operate reliably. Force the
+        * FreeSync range minimum to 55 Hz.
+        */
+       case drm_edid_encode_panel_id('A', 'C', 'R', 0x08AF):
+               drm_dbg_driver(dev, "Force FreeSync min to 55 Hz on panel id 
%X\n", panel_id);
+               edid_caps->panel_patch.force_freesync_min_hz = 55;
+               break;
+       /*
+        * Workaround for the Lenovo G34w-30 which reports a FreeSync
+        * minimum refresh rate (48 Hz) that fails to light up over DP.
+        * Force the FreeSync range minimum to 60 Hz.
+        */
+       case drm_edid_encode_panel_id('L', 'E', 'N', 0x66F1):
+               drm_dbg_driver(dev, "Force FreeSync min to 60 Hz on panel id 
%X\n", panel_id);
+               edid_caps->panel_patch.force_freesync_min_hz = 60;
+               break;
        default:
                return;
        }
diff --git 
a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c
index 058e1ad15dfe..5de697ca0fcc 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c
@@ -186,6 +186,22 @@ static void dm_test_apply_edid_quirks_skip_phy_ssc(struct 
kunit *test)
        KUNIT_EXPECT_TRUE(test, link->wa_flags.skip_phy_ssc_reduction);
 }
 
+/**
+ * dm_test_apply_edid_quirks_force_freesync_min - Test ACR 0x08AF FreeSync min 
quirk
+ * @test: The KUnit test context
+ */
+static void dm_test_apply_edid_quirks_force_freesync_min(struct kunit *test)
+{
+       struct dc_edid_caps edid_caps = {0};
+       struct dc_link *link = dm_test_quirk_link(test);
+       struct edid *edid = dm_test_edid_with_panel_id(test,
+                       drm_edid_encode_panel_id('A', 'C', 'R', 0x08AF));
+
+       apply_edid_quirks(link, edid, &edid_caps);
+
+       KUNIT_EXPECT_EQ(test, edid_caps.panel_patch.force_freesync_min_hz, 55U);
+}
+
 /**
  * dm_test_apply_edid_quirks_unknown_noop - Test unknown panel id is a no-op
  * @test: The KUnit test context
@@ -3724,6 +3740,7 @@ static struct kunit_case amdgpu_dm_helpers_test_cases[] = 
{
        KUNIT_CASE(dm_test_apply_edid_quirks_remove_sink_ext_caps),
        KUNIT_CASE(dm_test_apply_edid_quirks_disable_colorimetry),
        KUNIT_CASE(dm_test_apply_edid_quirks_skip_phy_ssc),
+       KUNIT_CASE(dm_test_apply_edid_quirks_force_freesync_min),
        KUNIT_CASE(dm_test_apply_edid_quirks_unknown_noop),
        /* dm_helpers_parse_edid_caps */
        KUNIT_CASE(dm_test_parse_edid_caps_null_edid),
diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h 
b/drivers/gpu/drm/amd/display/dc/dc_types.h
index 7da673111ed9..64b4adee36c4 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
@@ -194,6 +194,7 @@ struct dc_panel_patch {
        bool oled_optimize_display_on;
        unsigned int force_mst_blocked_discovery;
        unsigned int wait_after_dpcd_poweroff_ms;
+       unsigned int force_freesync_min_hz;
 };
 
 /**
-- 
2.43.0

Reply via email to