Commit 84d1ce06 authored by Jimmy Kizito's avatar Jimmy Kizito Committed by Alex Deucher

drm/amd/display: Add work around for AUX failure on wake.

[Why]
When waking from low-power states, a DP sink may remain unresponsive to
AUX transactions.

[How]
Try to toggle DPCD SET_POWER register repeatedly (up to a maximum
timeout value) until DP sink becomes responsive.
Reviewed-by: default avatarMustapha Ghaddar <Mustapha.Ghaddar@amd.com>
Acked-by: default avatarAlex Hung <alex.hung@amd.com>
Signed-off-by: default avatarJimmy Kizito <Jimmy.Kizito@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent a905f0b5
...@@ -5216,6 +5216,62 @@ static void retrieve_cable_id(struct dc_link *link) ...@@ -5216,6 +5216,62 @@ static void retrieve_cable_id(struct dc_link *link)
&link->dpcd_caps.cable_id, &usbc_cable_id); &link->dpcd_caps.cable_id, &usbc_cable_id);
} }
/* DPRX may take some time to respond to AUX messages after HPD asserted.
* If AUX read unsuccessful, try to wake unresponsive DPRX by toggling DPCD SET_POWER (0x600).
*/
static enum dc_status wa_try_to_wake_dprx(struct dc_link *link, uint64_t timeout_ms)
{
enum dc_status status = DC_ERROR_UNEXPECTED;
uint8_t dpcd_data = 0;
uint64_t start_ts = 0;
uint64_t current_ts = 0;
uint64_t time_taken_ms = 0;
enum dc_connection_type type = dc_connection_none;
status = core_link_read_dpcd(
link,
DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV,
&dpcd_data,
sizeof(dpcd_data));
if (status != DC_OK) {
DC_LOG_WARNING("%s: Read DPCD LTTPR_CAP failed - try to toggle DPCD SET_POWER for %lld ms.",
__func__,
timeout_ms);
start_ts = dm_get_timestamp(link->ctx);
do {
if (!dc_link_detect_sink(link, &type) || type == dc_connection_none)
break;
dpcd_data = DP_SET_POWER_D3;
status = core_link_write_dpcd(
link,
DP_SET_POWER,
&dpcd_data,
sizeof(dpcd_data));
dpcd_data = DP_SET_POWER_D0;
status = core_link_write_dpcd(
link,
DP_SET_POWER,
&dpcd_data,
sizeof(dpcd_data));
current_ts = dm_get_timestamp(link->ctx);
time_taken_ms = div_u64(dm_get_elapse_time_in_ns(link->ctx, current_ts, start_ts), 1000000);
} while (status != DC_OK && time_taken_ms < timeout_ms);
DC_LOG_WARNING("%s: DPCD SET_POWER %s after %lld ms%s",
__func__,
(status == DC_OK) ? "succeeded" : "failed",
time_taken_ms,
(type == dc_connection_none) ? ". Unplugged." : ".");
}
return status;
}
static bool retrieve_link_cap(struct dc_link *link) static bool retrieve_link_cap(struct dc_link *link)
{ {
/* DP_ADAPTER_CAP - DP_DPCD_REV + 1 == 16 and also DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT + 1 == 16, /* DP_ADAPTER_CAP - DP_DPCD_REV + 1 == 16 and also DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT + 1 == 16,
...@@ -5251,6 +5307,9 @@ static bool retrieve_link_cap(struct dc_link *link) ...@@ -5251,6 +5307,9 @@ static bool retrieve_link_cap(struct dc_link *link)
dc_link_aux_try_to_configure_timeout(link->ddc, dc_link_aux_try_to_configure_timeout(link->ddc,
LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD); LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD);
/* Try to ensure AUX channel active before proceeding. */
status = wa_try_to_wake_dprx(link, LINK_AUX_WAKE_TIMEOUT_MS);
is_lttpr_present = dp_retrieve_lttpr_cap(link); is_lttpr_present = dp_retrieve_lttpr_cap(link);
/* Read DP tunneling information. */ /* Read DP tunneling information. */
status = dpcd_get_tunneling_device_data(link); status = dpcd_get_tunneling_device_data(link);
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#define MAX_MTP_SLOT_COUNT 64 #define MAX_MTP_SLOT_COUNT 64
#define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50 #define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50
#define TRAINING_AUX_RD_INTERVAL 100 //us #define TRAINING_AUX_RD_INTERVAL 100 //us
#define LINK_AUX_WAKE_TIMEOUT_MS 1500 // Timeout when trying to wake unresponsive DPRX.
struct dc_link; struct dc_link;
struct dc_stream_state; struct dc_stream_state;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment