From: Fangzhi Zuo <jerry....@amd.com>

[why]
The first MST sideband message returns AUX_RET_ERROR_HPD_DISCON on
a certain Intel platform. Aux transaction is considered a failure if HPD
unexpectedly pulled low. The actual aux transaction success in such
case, hence do not return an error. Several Dell Intel-based Precision
systems had this issue, for example, Precision 3260 and 3460.

[how]
Not returning error when AUX_RET_ERROR_HPD_DISCON detected
on the first sideband message.

Changes since v1:
* Add two missing products

Cc: Harry Wentland <harry.wentl...@amd.com>
Cc: Mario Limonciello <mario.limoncie...@amd.com>
Cc: Qian Fu <qian...@dell.com>
Cc: sta...@vger.kernel.org
Signed-off-by: Fangzhi Zuo <jerry....@amd.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 29 +++++++++++++++++++
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  8 +++++
 .../display/amdgpu_dm/amdgpu_dm_mst_types.c   | 17 +++++++++++
 3 files changed, 54 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index de1c139ae279..3c7f6920f71f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -72,6 +72,7 @@
 #include <linux/pci.h>
 #include <linux/firmware.h>
 #include <linux/component.h>
+#include <linux/dmi.h>
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_uapi.h>
@@ -1400,6 +1401,31 @@ static bool dm_should_disable_stutter(struct pci_dev 
*pdev)
        return false;
 }
 
+static const struct dmi_system_id hpd_disconnect_quirk_table[] = {
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3660"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3260"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3460"),
+               },
+       },
+       {}
+};
+
+void retrieve_dmi_info(struct amdgpu_display_manager *dm)
+{
+       const struct dmi_system_id *dmi_id;
+
+       dm->aux_hpd_discon_quirk = false;
+
+       dmi_id = dmi_first_match(hpd_disconnect_quirk_table);
+       if (dmi_id) {
+               dm->aux_hpd_discon_quirk = true;
+               DRM_INFO("aux_hpd_discon_quirk attached\n");
+       }
+}
+
 static int amdgpu_dm_init(struct amdgpu_device *adev)
 {
        struct dc_init_data init_data;
@@ -1528,6 +1554,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
        init_data.flags.enable_mipi_converter_optimization = true;
 
        INIT_LIST_HEAD(&adev->dm.da_list);
+
+       retrieve_dmi_info(&adev->dm);
+
        /* Display Core create. */
        adev->dm.dc = dc_create(&init_data);
 
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index e04e6b3f609f..33d66d4897dc 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -547,6 +547,14 @@ struct amdgpu_display_manager {
         * last successfully applied backlight values.
         */
        u32 actual_brightness[AMDGPU_DM_MAX_NUM_EDP];
+
+       /**
+        * @aux_hpd_discon_quirk:
+        *
+        * quirk for hpd discon while aux is on-going.
+        * occurred on certain intel platform
+        */
+       bool aux_hpd_discon_quirk;
 };
 
 enum dsc_clock_force_state {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index 8237029cedf5..168d5676b657 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -56,6 +56,8 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux,
        ssize_t result = 0;
        struct aux_payload payload;
        enum aux_return_code_type operation_result;
+       struct amdgpu_device *adev;
+       struct ddc_service *ddc;
 
        if (WARN_ON(msg->size > 16))
                return -E2BIG;
@@ -74,6 +76,21 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux,
        result = dc_link_aux_transfer_raw(TO_DM_AUX(aux)->ddc_service, &payload,
                                      &operation_result);
 
+       /*
+        * w/a on certain intel platform where hpd is unexpected to pull low 
during
+        * 1st sideband message transaction by return AUX_RET_ERROR_HPD_DISCON
+        * aux transaction is succuess in such case, therefore bypass the error
+        */
+       ddc = TO_DM_AUX(aux)->ddc_service;
+       adev = ddc->ctx->driver_context;
+       if (adev->dm.aux_hpd_discon_quirk) {
+               if (msg->address == DP_SIDEBAND_MSG_DOWN_REQ_BASE &&
+                       operation_result == AUX_RET_ERROR_HPD_DISCON) {
+                       result = 0;
+                       operation_result = AUX_RET_SUCCESS;
+               }
+       }
+
        if (payload.write && result >= 0)
                result = msg->size;
 
-- 
2.37.0

Reply via email to