]> git.baikalelectronics.ru Git - kernel.git/commitdiff
drm/amd/display: implement T12 compliance
authorJun Lei <jun.lei@amd.com>
Tue, 24 Nov 2020 16:58:19 +0000 (11:58 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 14 Jan 2021 04:43:56 +0000 (23:43 -0500)
[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: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Jun Lei <jun.lei@amd.com>
Reviewed-by: Aric Cyr <Aric.Cyr@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/dc_link.h
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c
drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h

index 59ef1eacc6e1fc39c0e7a5eb2dad423afa7bf03c..4f58a5c43548aedc1568f53e54e3985c9d7d3901 100644 (file)
@@ -203,6 +203,17 @@ static bool program_hpd_filter(const struct dc_link *link)
        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
  *
index d8d659b2bc349842f83791b29b4486fed4ef75b6..d5d8f0ad92335b3003e5e6bb60676f5aa4d8b194 100644 (file)
@@ -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,
                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(
        struct dc_link *link,
        union hpd_irq_data *irq_data);
index 4c230f1de9a30e7daf1c1c828036213aa4cdb7c8..3e9abb1b8e14e1726928dc55f030c397836552f3 100644 (file)
@@ -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*/
 /*
  * @brief
index e5691e49902315f0165dc017ab68ff51b781c067..dee8ad1ebaa4e3efbc5525d60b441a131ab9f4f8 100644 (file)
@@ -163,6 +163,8 @@ void dcn10_wait_for_mpcc_disconnect(
 void dce110_edp_backlight_control(
                struct dc_link *link,
                bool enable);
+void dce110_edp_wait_for_T12(
+               struct dc_link *link);
 void dce110_edp_power_control(
                struct dc_link *link,
                bool power_up);
index 87c74aa844062435922baffa81a4d6eb2294501e..c4c14e9c1309c2653bbbab16e0843f8fecd0dd24 100644 (file)
@@ -71,6 +71,7 @@ static const struct hw_sequencer_funcs dcn30_funcs = {
        .edp_backlight_control = dce110_edp_backlight_control,
        .edp_power_control = dce110_edp_power_control,
        .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_attribute = dcn10_set_cursor_attribute,
        .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level,
index 7b12ffcdd4ec8c9e01f16240efa749dc2ac51b69..7a19ff5d42148c9ff6703776f42f928fcdfec1ca 100644 (file)
@@ -54,6 +54,7 @@ struct hw_sequencer_funcs {
        /* Embedded Display Related */
        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_T12)(struct dc_link *link);
 
        /* Pipe Programming Related */
        void (*init_hw)(struct dc *dc);