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: Mustapha Ghaddar <Mustapha.Ghaddar@amd.com> Acked-by: Alex Hung <alex.hung@amd.com> Signed-off-by: Jimmy Kizito <Jimmy.Kizito@amd.com> Tested-by: Daniel Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Родитель
83e9faac9a
Коммит
2944dbedc7
|
@ -5216,6 +5216,62 @@ static void retrieve_cable_id(struct dc_link *link)
|
|||
&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)
|
||||
{
|
||||
/* 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)
|
|||
dc_link_aux_try_to_configure_timeout(link->ddc,
|
||||
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);
|
||||
/* Read DP tunneling information. */
|
||||
status = dpcd_get_tunneling_device_data(link);
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#define MAX_MTP_SLOT_COUNT 64
|
||||
#define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50
|
||||
#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_stream_state;
|
||||
|
|
Загрузка…
Ссылка в новой задаче