[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 | 72 | #include <linux/pci.h> |
| 73 | 73 | #include <linux/firmware.h> |
| 74 | 74 | #include <linux/component.h> |
| 75 | +#include <linux/dmi.h> | |
| 75 | 76 | |
| 76 | 77 | #include <drm/display/drm_dp_mst_helper.h> |
| 77 | 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 | 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 | 1421 | static int amdgpu_dm_init(struct amdgpu_device *adev) |
| 1386 | 1422 | { |
| 1387 | 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 | 1546 | INIT_LIST_HEAD(&adev->dm.da_list); |
| 1547 | + | |
| 1548 | + retrieve_dmi_info(&adev->dm); | |
| 1549 | + | |
| 1511 | 1550 | /* Display Core create. */ |
| 1512 | 1551 | adev->dm.dc = dc_create(&init_data); |
| 1513 | 1552 | |
| @@ -540,6 +540,14 @@ struct amdgpu_display_manager { · 539 unmodified lines | ||
| 540 | 540 | * last successfully applied backlight values. |
| 541 | 541 | */ |
| 542 | 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 | 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 | 56 | ssize_t result = 0; |
| 57 | 57 | struct aux_payload payload; |
| 58 | 58 | enum aux_return_code_type operation_result; |
| 59 | + struct amdgpu_device *adev; | |
| 60 | + struct ddc_service *ddc; | |
| 59 | 61 | |
| 60 | 62 | if (WARN_ON(msg->size > 16)) |
| 61 | 63 | return -E2BIG; |
| @@ -74,6 +76,21 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, · 12 unmodified lines | ||
| 74 | 76 | result = dc_link_aux_transfer_raw(TO_DM_AUX(aux)->ddc_service, &payload, |
| 75 | 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 | 94 | if (payload.write && result >= 0) |
| 78 | 95 | result = msg->size; |
| 79 | 96 | |