Commit cf3a2627 authored by Jun Lei's avatar Jun Lei Committed by Alex Deucher

drm/amd/display: implement T12 compliance

[why]
When OS reboots, and panel is turned off, T12 may not be maintained.
T12 is defined as the interval between VDDC off (occurs at shutdown) and
the next VDDC on (occurs when eDP is POST-ed)

[how]
DC already tracks panel power off time.  Add a DC interface which DM can
call during shutdown.  Ideally this should be as late as possible during
the shutdown sequence so the extra delay is minimal.
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarJun Lei <jun.lei@amd.com>
Reviewed-by: default avatarAric Cyr <Aric.Cyr@amd.com>
Acked-by: default avatarRodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent ea0124a7
...@@ -203,6 +203,17 @@ static bool program_hpd_filter(const struct dc_link *link) ...@@ -203,6 +203,17 @@ static bool program_hpd_filter(const struct dc_link *link)
return result; return result;
} }
bool dc_link_wait_for_t12(struct dc_link *link)
{
if (link->connector_signal == SIGNAL_TYPE_EDP && link->dc->hwss.edp_wait_for_T12) {
link->dc->hwss.edp_wait_for_T12(link);
return true;
}
return false;
}
/** /**
* dc_link_detect_sink() - Determine if there is a sink connected * dc_link_detect_sink() - Determine if there is a sink connected
* *
......
...@@ -259,6 +259,13 @@ enum dc_status dc_link_reallocate_mst_payload(struct dc_link *link); ...@@ -259,6 +259,13 @@ enum dc_status dc_link_reallocate_mst_payload(struct dc_link *link);
bool dc_link_handle_hpd_rx_irq(struct dc_link *dc_link, bool dc_link_handle_hpd_rx_irq(struct dc_link *dc_link,
union hpd_irq_data *hpd_irq_dpcd_data, bool *out_link_loss); union hpd_irq_data *hpd_irq_dpcd_data, bool *out_link_loss);
/*
* On eDP links this function call will stall until T12 has elapsed.
* If the panel is not in power off state, this function will return
* immediately.
*/
bool dc_link_wait_for_t12(struct dc_link *link);
enum dc_status read_hpd_rx_irq_data( enum dc_status read_hpd_rx_irq_data(
struct dc_link *link, struct dc_link *link,
union hpd_irq_data *irq_data); union hpd_irq_data *irq_data);
......
...@@ -921,6 +921,37 @@ void dce110_edp_power_control( ...@@ -921,6 +921,37 @@ void dce110_edp_power_control(
} }
} }
void dce110_edp_wait_for_T12(
struct dc_link *link)
{
struct dc_context *ctx = link->ctx;
if (dal_graphics_object_id_get_connector_id(link->link_enc->connector)
!= CONNECTOR_ID_EDP) {
BREAK_TO_DEBUGGER();
return;
}
if (!link->panel_cntl)
return;
if (!link->panel_cntl->funcs->is_panel_powered_on(link->panel_cntl) &&
link->link_trace.time_stamp.edp_poweroff != 0) {
unsigned int t12_duration = 500; // Default T12 as per spec
unsigned long long current_ts = dm_get_timestamp(ctx);
unsigned long long time_since_edp_poweroff_ms =
div64_u64(dm_get_elapse_time_in_ns(
ctx,
current_ts,
link->link_trace.time_stamp.edp_poweroff), 1000000);
t12_duration += link->local_sink->edid_caps.panel_patch.extra_t12_ms; // Add extra T12
if (time_since_edp_poweroff_ms < t12_duration)
msleep(t12_duration - time_since_edp_poweroff_ms);
}
}
/*todo: cloned in stream enc, fix*/ /*todo: cloned in stream enc, fix*/
/* /*
* @brief * @brief
......
...@@ -163,6 +163,8 @@ void dcn10_wait_for_mpcc_disconnect( ...@@ -163,6 +163,8 @@ void dcn10_wait_for_mpcc_disconnect(
void dce110_edp_backlight_control( void dce110_edp_backlight_control(
struct dc_link *link, struct dc_link *link,
bool enable); bool enable);
void dce110_edp_wait_for_T12(
struct dc_link *link);
void dce110_edp_power_control( void dce110_edp_power_control(
struct dc_link *link, struct dc_link *link,
bool power_up); bool power_up);
......
...@@ -71,6 +71,7 @@ static const struct hw_sequencer_funcs dcn30_funcs = { ...@@ -71,6 +71,7 @@ static const struct hw_sequencer_funcs dcn30_funcs = {
.edp_backlight_control = dce110_edp_backlight_control, .edp_backlight_control = dce110_edp_backlight_control,
.edp_power_control = dce110_edp_power_control, .edp_power_control = dce110_edp_power_control,
.edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready,
.edp_wait_for_T12 = dce110_edp_wait_for_T12,
.set_cursor_position = dcn10_set_cursor_position, .set_cursor_position = dcn10_set_cursor_position,
.set_cursor_attribute = dcn10_set_cursor_attribute, .set_cursor_attribute = dcn10_set_cursor_attribute,
.set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level,
......
...@@ -54,6 +54,7 @@ struct hw_sequencer_funcs { ...@@ -54,6 +54,7 @@ struct hw_sequencer_funcs {
/* Embedded Display Related */ /* Embedded Display Related */
void (*edp_power_control)(struct dc_link *link, bool enable); void (*edp_power_control)(struct dc_link *link, bool enable);
void (*edp_wait_for_hpd_ready)(struct dc_link *link, bool power_up); void (*edp_wait_for_hpd_ready)(struct dc_link *link, bool power_up);
void (*edp_wait_for_T12)(struct dc_link *link);
/* Pipe Programming Related */ /* Pipe Programming Related */
void (*init_hw)(struct dc *dc); void (*init_hw)(struct dc *dc);
......
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