[why] First MST sideband message returns AUX_RET_ERROR_HPD_DISCON on certain intel platform. Aux transaction considered failure if HPD unexpected pulled low. The actual aux transaction success in such case, hence do not return error. [how] Not returning error when AUX_RET_ERROR_HPD_DISCON detected on the first sideband message. v2: squash in additional DMI entries v3: squash in static fix
Unified · Split
| @@ -72,6 +72,7 @@ · 71 unmodified lines | |||
| 72 | #include <linux/pci.h> | 72 | #include <linux/pci.h> |
| 73 | #include <linux/firmware.h> | 73 | #include <linux/firmware.h> |
| 74 | #include <linux/component.h> | 74 | #include <linux/component.h> |
| 75 | #include <linux/dmi.h> | ||
| 75 | 76 | ||
| 76 | #include <drm/display/drm_dp_mst_helper.h> | 77 | #include <drm/display/drm_dp_mst_helper.h> |
| 77 | #include <drm/display/drm_hdmi_helper.h> | 78 | #include <drm/display/drm_hdmi_helper.h> |
| @@ -1382,6 +1383,41 @@ static bool dm_should_disable_stutter(struct pci_dev *pdev) · 1304 unmodified lines | |||
| 1382 | return false; | 1383 | return false; |
| 1383 | } | 1384 | } |
| 1384 | 1385 | ||
| 1386 | static const struct dmi_system_id hpd_disconnect_quirk_table[] = { | ||
| 1387 | { | ||
| 1388 | .matches = { | ||
| 1389 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | ||
| 1390 | DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3660"), | ||
| 1391 | }, | ||
| 1392 | }, | ||
| 1393 | { | ||
| 1394 | .matches = { | ||
| 1395 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | ||
| 1396 | DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3260"), | ||
| 1397 | }, | ||
| 1398 | }, | ||
| 1399 | { | ||
| 1400 | .matches = { | ||
| 1401 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | ||
| 1402 | DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3460"), | ||
| 1403 | }, | ||
| 1404 | }, | ||
| 1405 | {} | ||
| 1406 | }; | ||
| 1407 | |||
| 1408 | static void retrieve_dmi_info(struct amdgpu_display_manager *dm) | ||
| 1409 | { | ||
| 1410 | const struct dmi_system_id *dmi_id; | ||
| 1411 | |||
| 1412 | dm->aux_hpd_discon_quirk = false; | ||
| 1413 | |||
| 1414 | dmi_id = dmi_first_match(hpd_disconnect_quirk_table); | ||
| 1415 | if (dmi_id) { | ||
| 1416 | dm->aux_hpd_discon_quirk = true; | ||
| 1417 | DRM_INFO("aux_hpd_discon_quirk attached\n"); | ||
| 1418 | } | ||
| 1419 | } | ||
| 1420 | |||
| 1385 | static int amdgpu_dm_init(struct amdgpu_device *adev) | 1421 | static int amdgpu_dm_init(struct amdgpu_device *adev) |
| 1386 | { | 1422 | { |
| 1387 | struct dc_init_data init_data; | 1423 | struct dc_init_data init_data; |
| @@ -1508,6 +1544,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) · 120 unmodified lines | |||
| 1508 | } | 1544 | } |
| 1509 | 1545 | ||
| 1510 | INIT_LIST_HEAD(&adev->dm.da_list); | 1546 | INIT_LIST_HEAD(&adev->dm.da_list); |
| 1547 | |||
| 1548 | retrieve_dmi_info(&adev->dm); | ||
| 1549 | |||
| 1511 | /* Display Core create. */ | 1550 | /* Display Core create. */ |
| 1512 | adev->dm.dc = dc_create(&init_data); | 1551 | adev->dm.dc = dc_create(&init_data); |
| 1513 | 1552 | ||
| @@ -540,6 +540,14 @@ struct amdgpu_display_manager { · 539 unmodified lines | |||
| 540 | * last successfully applied backlight values. | 540 | * last successfully applied backlight values. |
| 541 | */ | 541 | */ |
| 542 | u32 actual_brightness[AMDGPU_DM_MAX_NUM_EDP]; | 542 | u32 actual_brightness[AMDGPU_DM_MAX_NUM_EDP]; |
| 543 | |||
| 544 | /** | ||
| 545 | * @aux_hpd_discon_quirk: | ||
| 546 | * | ||
| 547 | * quirk for hpd discon while aux is on-going. | ||
| 548 | * occurred on certain intel platform | ||
| 549 | */ | ||
| 550 | bool aux_hpd_discon_quirk; | ||
| 543 | }; | 551 | }; |
| 544 | 552 | ||
| 545 | enum dsc_clock_force_state { | 553 | enum dsc_clock_force_state { |
| @@ -56,6 +56,8 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, · 55 unmodified lines | |||
| 56 | ssize_t result = 0; | 56 | ssize_t result = 0; |
| 57 | struct aux_payload payload; | 57 | struct aux_payload payload; |
| 58 | enum aux_return_code_type operation_result; | 58 | enum aux_return_code_type operation_result; |
| 59 | struct amdgpu_device *adev; | ||
| 60 | struct ddc_service *ddc; | ||
| 59 | 61 | ||
| 60 | if (WARN_ON(msg->size > 16)) | 62 | if (WARN_ON(msg->size > 16)) |
| 61 | return -E2BIG; | 63 | return -E2BIG; |
| @@ -74,6 +76,21 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, · 12 unmodified lines | |||
| 74 | result = dc_link_aux_transfer_raw(TO_DM_AUX(aux)->ddc_service, &payload, | 76 | result = dc_link_aux_transfer_raw(TO_DM_AUX(aux)->ddc_service, &payload, |
| 75 | &operation_result); | 77 | &operation_result); |
| 76 | 78 | ||
| 79 | /* | ||
| 80 | * w/a on certain intel platform where hpd is unexpected to pull low during | ||
| 81 | * 1st sideband message transaction by return AUX_RET_ERROR_HPD_DISCON | ||
| 82 | * aux transaction is succuess in such case, therefore bypass the error | ||
| 83 | */ | ||
| 84 | ddc = TO_DM_AUX(aux)->ddc_service; | ||
| 85 | adev = ddc->ctx->driver_context; | ||
| 86 | if (adev->dm.aux_hpd_discon_quirk) { | ||
| 87 | if (msg->address == DP_SIDEBAND_MSG_DOWN_REQ_BASE && | ||
| 88 | operation_result == AUX_RET_ERROR_HPD_DISCON) { | ||
| 89 | result = 0; | ||
| 90 | operation_result = AUX_RET_SUCCESS; | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 77 | if (payload.write && result >= 0) | 94 | if (payload.write && result >= 0) |
| 78 | result = msg->size; | 95 | result = msg->size; |
| 79 | 96 | ||