aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/2507-drm-amd-display-Move-power-control-from-link-encoder.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/2507-drm-amd-display-Move-power-control-from-link-encoder.patch')
-rw-r--r--meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/2507-drm-amd-display-Move-power-control-from-link-encoder.patch792
1 files changed, 792 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/2507-drm-amd-display-Move-power-control-from-link-encoder.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/2507-drm-amd-display-Move-power-control-from-link-encoder.patch
new file mode 100644
index 00000000..60bb7657
--- /dev/null
+++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/2507-drm-amd-display-Move-power-control-from-link-encoder.patch
@@ -0,0 +1,792 @@
+From 508ebcf6da1a714ff2c2c3a3797ebc7ac787b76b Mon Sep 17 00:00:00 2001
+From: Andrew Jiang <Andrew.Jiang@amd.com>
+Date: Mon, 25 Sep 2017 18:03:14 -0400
+Subject: [PATCH 2507/4131] drm/amd/display: Move power control from link
+ encoder to hwsequencer
+
+A recent commit moved the backlight control code along with the register
+defines, but did not move the power control code. This along with
+remnant fields in the dce110_link_enc_registers struct made it so that
+the code still compiled, but any attempts to access the
+LVTMA_PWRSEQ_STATE register led to reading from an address of 0. This
+patch corrects that.
+
+Also, rename blacklight_control to edp_backlight_control (Typo fix).
+
+Signed-off-by: Andrew Jiang <Andrew.Jiang@amd.com>
+Reviewed-by: Tony Cheng <Tony.Cheng@amd.com>
+Acked-by: Harry Wentland <Harry.Wentland@amd.com>
+---
+ drivers/gpu/drm/amd/display/dc/core/dc_link.c | 17 +-
+ drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c | 8 +-
+ drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h | 18 ++-
+ .../gpu/drm/amd/display/dc/dce/dce_link_encoder.c | 171 +--------------------
+ .../gpu/drm/amd/display/dc/dce/dce_link_encoder.h | 8 -
+ .../amd/display/dc/dce110/dce110_hw_sequencer.c | 155 +++++++++++++++++--
+ .../amd/display/dc/dce110/dce110_hw_sequencer.h | 6 +-
+ .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 3 +-
+ .../gpu/drm/amd/display/dc/inc/hw/link_encoder.h | 2 -
+ drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h | 7 +-
+ drivers/gpu/drm/amd/display/dc/inc/link_hwss.h | 4 +
+ .../amd/display/dc/virtual/virtual_link_encoder.c | 5 -
+ 12 files changed, 190 insertions(+), 214 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+index a58e61b..feb10be 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+@@ -78,14 +78,15 @@ static void destruct(struct dc_link *link)
+ dc_sink_release(link->remote_sinks[i]);
+ }
+
+-static struct gpio *get_hpd_gpio(const struct dc_link *link)
++struct gpio *get_hpd_gpio(struct dc_bios *dcb,
++ struct graphics_object_id link_id,
++ struct gpio_service *gpio_service)
+ {
+ enum bp_result bp_result;
+- struct dc_bios *dcb = link->ctx->dc_bios;
+ struct graphics_object_hpd_info hpd_info;
+ struct gpio_pin_info pin_info;
+
+- if (dcb->funcs->get_hpd_info(dcb, link->link_id, &hpd_info) != BP_RESULT_OK)
++ if (dcb->funcs->get_hpd_info(dcb, link_id, &hpd_info) != BP_RESULT_OK)
+ return NULL;
+
+ bp_result = dcb->funcs->get_gpio_pin_info(dcb,
+@@ -97,7 +98,7 @@ static struct gpio *get_hpd_gpio(const struct dc_link *link)
+ }
+
+ return dal_gpio_service_create_irq(
+- link->ctx->gpio_service,
++ gpio_service,
+ pin_info.offset,
+ pin_info.mask);
+ }
+@@ -153,7 +154,7 @@ static bool program_hpd_filter(
+ }
+
+ /* Obtain HPD handle */
+- hpd = get_hpd_gpio(link);
++ hpd = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service);
+
+ if (!hpd)
+ return result;
+@@ -186,7 +187,7 @@ static bool detect_sink(struct dc_link *link, enum dc_connection_type *type)
+ struct gpio *hpd_pin;
+
+ /* todo: may need to lock gpio access */
+- hpd_pin = get_hpd_gpio(link);
++ hpd_pin = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service);
+ if (hpd_pin == NULL)
+ goto hpd_gpio_failure;
+
+@@ -795,7 +796,7 @@ static enum hpd_source_id get_hpd_line(
+ struct gpio *hpd;
+ enum hpd_source_id hpd_id = HPD_SOURCEID_UNKNOWN;
+
+- hpd = get_hpd_gpio(link);
++ hpd = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service);
+
+ if (hpd) {
+ switch (dal_irq_get_source(hpd)) {
+@@ -965,7 +966,7 @@ static bool construct(
+ goto create_fail;
+ }
+
+- hpd_gpio = get_hpd_gpio(link);
++ hpd_gpio = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service);
+
+ if (hpd_gpio != NULL)
+ link->irq_source_hpd = dal_irq_get_source(hpd_gpio);
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
+index fa22505..34b6d1c 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
+@@ -89,12 +89,12 @@ void dp_enable_link_phy(
+
+ if (dc_is_dp_sst_signal(signal)) {
+ if (signal == SIGNAL_TYPE_EDP) {
+- link_enc->funcs->power_control(link_enc, true);
++ link->dc->hwss.edp_power_control(link->link_enc, true);
+ link_enc->funcs->enable_dp_output(
+ link_enc,
+ link_settings,
+ clock_source);
+- link->dc->hwss.backlight_control(link, true);
++ link->dc->hwss.edp_backlight_control(link, true);
+ } else
+ link_enc->funcs->enable_dp_output(
+ link_enc,
+@@ -138,10 +138,10 @@ void dp_disable_link_phy(struct dc_link *link, enum signal_type signal)
+ dp_receiver_power_ctrl(link, false);
+
+ if (signal == SIGNAL_TYPE_EDP) {
+- link->dc->hwss.backlight_control(link, false);
++ link->dc->hwss.edp_backlight_control(link, false);
+ edp_receiver_ready_T9(link);
+ link->link_enc->funcs->disable_output(link->link_enc, signal, link);
+- link->link_enc->funcs->power_control(link->link_enc, false);
++ link->dc->hwss.edp_power_control(link->link_enc, false);
+ } else
+ link->link_enc->funcs->disable_output(link->link_enc, signal, link);
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h
+index 227c9b6..0a058e0 100644
+--- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h
++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h
+@@ -391,23 +391,27 @@ struct dce_hwseq_registers {
+ HWS_SF(BLND_, V_UPDATE_LOCK, BLND_DCP_GRPH_SURF_V_UPDATE_LOCK, mask_sh),\
+ HWS_SF(BLND_, CONTROL, BLND_MODE, mask_sh),\
+ HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh),\
++ HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh),\
+ HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_)
+
+ #define HWSEQ_DCE10_MASK_SH_LIST(mask_sh)\
+ HWSEQ_DCEF_MASK_SH_LIST(mask_sh, DCFE_),\
+ HWSEQ_BLND_MASK_SH_LIST(mask_sh, BLND_),\
+ HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_), \
+- HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh)
++ HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \
++ HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh)
+
+ #define HWSEQ_DCE11_MASK_SH_LIST(mask_sh)\
+ HWSEQ_DCE10_MASK_SH_LIST(mask_sh),\
+ SF(DCFEV_CLOCK_CONTROL, DCFEV_CLOCK_ENABLE, mask_sh),\
+ HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh),\
++ HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh),\
+ HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_)
+
+ #define HWSEQ_DCE112_MASK_SH_LIST(mask_sh)\
+ HWSEQ_DCE10_MASK_SH_LIST(mask_sh),\
+ HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh),\
++ HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh),\
+ HWSEQ_PHYPLL_MASK_SH_LIST(mask_sh, CRTC0_)
+
+ #define HWSEQ_GFX9_DCHUB_MASK_SH_LIST(mask_sh)\
+@@ -416,7 +420,8 @@ struct dce_hwseq_registers {
+ SF(DCHUB_AGP_BASE, AGP_BASE, mask_sh),\
+ SF(DCHUB_AGP_BOT, AGP_BOT, mask_sh),\
+ SF(DCHUB_AGP_TOP, AGP_TOP, mask_sh), \
+- HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh)
++ HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \
++ HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh)
+
+ #define HWSEQ_DCE12_MASK_SH_LIST(mask_sh)\
+ HWSEQ_DCEF_MASK_SH_LIST(mask_sh, DCFE0_DCFE_),\
+@@ -424,7 +429,8 @@ struct dce_hwseq_registers {
+ HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_),\
+ HWSEQ_PHYPLL_MASK_SH_LIST(mask_sh, CRTC0_),\
+ HWSEQ_GFX9_DCHUB_MASK_SH_LIST(mask_sh), \
+- HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh)
++ HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \
++ HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh)
+
+ #define HWSEQ_DCN_MASK_SH_LIST(mask_sh)\
+ HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, OTG0_),\
+@@ -489,7 +495,8 @@ struct dce_hwseq_registers {
+ HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \
+ HWS_SF(, DOMAIN7_PG_STATUS, DOMAIN7_PGFSM_PWR_STATUS, mask_sh), \
+ HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \
+- HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh)
++ HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \
++ HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh)
+
+ #define HWSEQ_REG_FIELD_LIST(type) \
+ type DCFE_CLOCK_ENABLE; \
+@@ -520,7 +527,8 @@ struct dce_hwseq_registers {
+ type LOGICAL_ADDR; \
+ type ENABLE_L1_TLB;\
+ type SYSTEM_ACCESS_MODE;\
+- type LVTMA_BLON;
++ type LVTMA_BLON;\
++ type LVTMA_PWRSEQ_TARGET_STATE_R;
+
+ #define HWSEQ_DCN_REG_FIELD_LIST(type) \
+ type VUPDATE_NO_LOCK_EVENT_CLEAR; \
+diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c
+index 1cb727b..0cf0fff 100644
+--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c
++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c
+@@ -82,13 +82,6 @@
+ #define DCE110_DIG_FE_SOURCE_SELECT_DIGF 0x20
+ #define DCE110_DIG_FE_SOURCE_SELECT_DIGG 0x40
+
+-/* all values are in milliseconds */
+-/* For eDP, after power-up/power/down,
+- * 300/500 msec max. delay from LCDVCC to black video generation */
+-#define PANEL_POWER_UP_TIMEOUT 300
+-#define PANEL_POWER_DOWN_TIMEOUT 500
+-#define HPD_CHECK_INTERVAL 10
+-
+ /* Minimum pixel clock, in KHz. For TMDS signal is 25.00 MHz */
+ #define TMDS_MIN_PIXEL_CLOCK 25000
+ /* Maximum pixel clock, in KHz. For TMDS signal is 165.00 MHz */
+@@ -122,7 +115,6 @@ static const struct link_encoder_funcs dce110_lnk_enc_funcs = {
+ .psr_program_dp_dphy_fast_training =
+ dce110_psr_program_dp_dphy_fast_training,
+ .psr_program_secondary_packet = dce110_psr_program_secondary_packet,
+- .power_control = dce110_link_encoder_edp_power_control,
+ .connect_dig_be_to_fe = dce110_link_encoder_connect_dig_be_to_fe,
+ .enable_hpd = dce110_link_encoder_enable_hpd,
+ .disable_hpd = dce110_link_encoder_disable_hpd,
+@@ -492,165 +484,6 @@ static void configure_encoder(
+ REG_UPDATE(DP_DPHY_SCRAM_CNTL, DPHY_SCRAMBLER_ADVANCE, 1);
+ }
+
+-static bool is_panel_powered_on(struct dce110_link_encoder *enc110)
+-{
+- bool ret;
+- uint32_t value;
+-
+- REG_GET(LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, &value);
+- ret = value;
+-
+- return ret == 1;
+-}
+-
+-
+-/* TODO duplicate of dc_link.c version */
+-static struct gpio *get_hpd_gpio(const struct link_encoder *enc)
+-{
+- enum bp_result bp_result;
+- struct dc_bios *dcb = enc->ctx->dc_bios;
+- struct graphics_object_hpd_info hpd_info;
+- struct gpio_pin_info pin_info;
+-
+- if (dcb->funcs->get_hpd_info(dcb, enc->connector, &hpd_info) != BP_RESULT_OK)
+- return NULL;
+-
+- bp_result = dcb->funcs->get_gpio_pin_info(dcb,
+- hpd_info.hpd_int_gpio_uid, &pin_info);
+-
+- if (bp_result != BP_RESULT_OK) {
+- ASSERT(bp_result == BP_RESULT_NORECORD);
+- return NULL;
+- }
+-
+- return dal_gpio_service_create_irq(
+- enc->ctx->gpio_service,
+- pin_info.offset,
+- pin_info.mask);
+-}
+-
+-/*
+- * @brief
+- * eDP only.
+- */
+-static void link_encoder_edp_wait_for_hpd_ready(
+- struct dce110_link_encoder *enc110,
+- bool power_up)
+-{
+- struct dc_context *ctx = enc110->base.ctx;
+- struct graphics_object_id connector = enc110->base.connector;
+- struct gpio *hpd;
+- bool edp_hpd_high = false;
+- uint32_t time_elapsed = 0;
+- uint32_t timeout = power_up ?
+- PANEL_POWER_UP_TIMEOUT : PANEL_POWER_DOWN_TIMEOUT;
+-
+- if (dal_graphics_object_id_get_connector_id(connector) !=
+- CONNECTOR_ID_EDP) {
+- BREAK_TO_DEBUGGER();
+- return;
+- }
+-
+- if (!power_up)
+- /* from KV, we will not HPD low after turning off VCC -
+- * instead, we will check the SW timer in power_up(). */
+- return;
+-
+- /* when we power on/off the eDP panel,
+- * we need to wait until SENSE bit is high/low */
+-
+- /* obtain HPD */
+- /* TODO what to do with this? */
+- hpd = get_hpd_gpio(&enc110->base);
+-
+- if (!hpd) {
+- BREAK_TO_DEBUGGER();
+- return;
+- }
+-
+- dal_gpio_open(hpd, GPIO_MODE_INTERRUPT);
+-
+- /* wait until timeout or panel detected */
+-
+- do {
+- uint32_t detected = 0;
+-
+- dal_gpio_get_value(hpd, &detected);
+-
+- if (!(detected ^ power_up)) {
+- edp_hpd_high = true;
+- break;
+- }
+-
+- msleep(HPD_CHECK_INTERVAL);
+-
+- time_elapsed += HPD_CHECK_INTERVAL;
+- } while (time_elapsed < timeout);
+-
+- dal_gpio_close(hpd);
+-
+- dal_gpio_destroy_irq(&hpd);
+-
+- if (false == edp_hpd_high) {
+- dm_logger_write(ctx->logger, LOG_ERROR,
+- "%s: wait timed out!\n", __func__);
+- }
+-}
+-
+-/*
+- * @brief
+- * eDP only. Control the power of the eDP panel.
+- */
+-void dce110_link_encoder_edp_power_control(
+- struct link_encoder *enc,
+- bool power_up)
+-{
+- struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
+- struct dc_context *ctx = enc110->base.ctx;
+- struct bp_transmitter_control cntl = { 0 };
+- enum bp_result bp_result;
+-
+- if (dal_graphics_object_id_get_connector_id(enc110->base.connector) !=
+- CONNECTOR_ID_EDP) {
+- BREAK_TO_DEBUGGER();
+- return;
+- }
+-
+- if ((power_up && !is_panel_powered_on(enc110)) ||
+- (!power_up && is_panel_powered_on(enc110))) {
+-
+- /* Send VBIOS command to prompt eDP panel power */
+-
+- dm_logger_write(ctx->logger, LOG_HW_RESUME_S3,
+- "%s: Panel Power action: %s\n",
+- __func__, (power_up ? "On":"Off"));
+-
+- cntl.action = power_up ?
+- TRANSMITTER_CONTROL_POWER_ON :
+- TRANSMITTER_CONTROL_POWER_OFF;
+- cntl.transmitter = enc110->base.transmitter;
+- cntl.connector_obj_id = enc110->base.connector;
+- cntl.coherent = false;
+- cntl.lanes_number = LANE_COUNT_FOUR;
+- cntl.hpd_sel = enc110->base.hpd_source;
+-
+- bp_result = link_transmitter_control(enc110, &cntl);
+-
+- if (BP_RESULT_OK != bp_result) {
+-
+- dm_logger_write(ctx->logger, LOG_ERROR,
+- "%s: Panel Power bp_result: %d\n",
+- __func__, bp_result);
+- }
+- } else {
+- dm_logger_write(ctx->logger, LOG_HW_RESUME_S3,
+- "%s: Skipping Panel Power action: %s\n",
+- __func__, (power_up ? "On":"Off"));
+- }
+-
+- link_encoder_edp_wait_for_hpd_ready(enc110, true);
+-}
+-
+ static void aux_initialize(
+ struct dce110_link_encoder *enc110)
+ {
+@@ -1018,7 +851,7 @@ void dce110_link_encoder_hw_init(
+ ASSERT(result == BP_RESULT_OK);
+
+ } else if (enc110->base.connector.id == CONNECTOR_ID_EDP) {
+- enc->funcs->power_control(&enc110->base, true);
++ ctx->dc->hwss.edp_power_control(enc, true);
+ }
+ aux_initialize(enc110);
+
+@@ -1218,7 +1051,7 @@ void dce110_link_encoder_disable_output(
+ return;
+ }
+ if (enc110->base.connector.id == CONNECTOR_ID_EDP)
+- ctx->dc->hwss.backlight_control(link, false);
++ ctx->dc->hwss.edp_backlight_control(link, false);
+ /* Power-down RX and disable GPU PHY should be paired.
+ * Disabling PHY without powering down RX may cause
+ * symbol lock loss, on which we will get DP Sink interrupt. */
+diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h
+index c65def5..494067d 100644
+--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h
++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h
+@@ -114,10 +114,6 @@ struct dce110_link_enc_hpd_registers {
+ };
+
+ struct dce110_link_enc_registers {
+- /* Backlight registers */
+- uint32_t LVTMA_PWRSEQ_CNTL;
+- uint32_t LVTMA_PWRSEQ_STATE;
+-
+ /* DMCU registers */
+ uint32_t MASTER_COMM_DATA_REG1;
+ uint32_t MASTER_COMM_DATA_REG2;
+@@ -250,10 +246,6 @@ void dce110_link_encoder_update_mst_stream_allocation_table(
+ struct link_encoder *enc,
+ const struct link_mst_stream_allocation_table *table);
+
+-void dce110_link_encoder_edp_power_control(
+- struct link_encoder *enc,
+- bool power_up);
+-
+ void dce110_link_encoder_connect_dig_be_to_fe(
+ struct link_encoder *enc,
+ enum engine_id engine,
+diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
+index d686811..8b7b1be 100644
+--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
++++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
+@@ -32,6 +32,7 @@
+ #include "dce110_hw_sequencer.h"
+ #include "dce110_timing_generator.h"
+ #include "dce/dce_hwseq.h"
++#include "gpio_service_interface.h"
+
+ #ifdef ENABLE_FBC
+ #include "dce110_compressor.h"
+@@ -45,10 +46,10 @@
+ #include "transform.h"
+ #include "stream_encoder.h"
+ #include "link_encoder.h"
++#include "link_hwss.h"
+ #include "clock_source.h"
+ #include "abm.h"
+ #include "audio.h"
+-#include "dce/dce_hwseq.h"
+ #include "reg_helper.h"
+
+ /* include DCE11 register header files */
+@@ -56,6 +57,15 @@
+ #include "dce/dce_11_0_sh_mask.h"
+ #include "custom_float.h"
+
++/*
++ * All values are in milliseconds;
++ * For eDP, after power-up/power/down,
++ * 300/500 msec max. delay from LCDVCC to black video generation
++ */
++#define PANEL_POWER_UP_TIMEOUT 300
++#define PANEL_POWER_DOWN_TIMEOUT 500
++#define HPD_CHECK_INTERVAL 10
++
+ #define CTX \
+ hws->ctx
+ #define REG(reg)\
+@@ -780,25 +790,150 @@ static bool is_panel_backlight_on(struct dce_hwseq *hws)
+ return value;
+ }
+
++static bool is_panel_powered_on(struct dce_hwseq *hws)
++{
++ uint32_t value;
++
++ REG_GET(LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, &value);
++ return value == 1;
++}
++
+ static enum bp_result link_transmitter_control(
+- struct dc_link *link,
++ struct dc_bios *bios,
+ struct bp_transmitter_control *cntl)
+ {
+ enum bp_result result;
+- struct dc_bios *bp = link->dc->ctx->dc_bios;
+
+- result = bp->funcs->transmitter_control(bp, cntl);
++ result = bios->funcs->transmitter_control(bios, cntl);
+
+ return result;
+ }
+
++/*
++ * @brief
++ * eDP only.
++ */
++void hwss_edp_wait_for_hpd_ready(
++ struct link_encoder *enc,
++ bool power_up)
++{
++ struct dc_context *ctx = enc->ctx;
++ struct graphics_object_id connector = enc->connector;
++ struct gpio *hpd;
++ bool edp_hpd_high = false;
++ uint32_t time_elapsed = 0;
++ uint32_t timeout = power_up ?
++ PANEL_POWER_UP_TIMEOUT : PANEL_POWER_DOWN_TIMEOUT;
++
++ if (dal_graphics_object_id_get_connector_id(connector)
++ != CONNECTOR_ID_EDP) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ if (!power_up)
++ /*
++ * From KV, we will not HPD low after turning off VCC -
++ * instead, we will check the SW timer in power_up().
++ */
++ return;
++
++ /*
++ * When we power on/off the eDP panel,
++ * we need to wait until SENSE bit is high/low.
++ */
++
++ /* obtain HPD */
++ /* TODO what to do with this? */
++ hpd = get_hpd_gpio(ctx->dc_bios, connector, ctx->gpio_service);
++
++ if (!hpd) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ dal_gpio_open(hpd, GPIO_MODE_INTERRUPT);
++
++ /* wait until timeout or panel detected */
++
++ do {
++ uint32_t detected = 0;
++
++ dal_gpio_get_value(hpd, &detected);
++
++ if (!(detected ^ power_up)) {
++ edp_hpd_high = true;
++ break;
++ }
++
++ msleep(HPD_CHECK_INTERVAL);
++
++ time_elapsed += HPD_CHECK_INTERVAL;
++ } while (time_elapsed < timeout);
++
++ dal_gpio_close(hpd);
++
++ dal_gpio_destroy_irq(&hpd);
++
++ if (false == edp_hpd_high) {
++ dm_logger_write(ctx->logger, LOG_ERROR,
++ "%s: wait timed out!\n", __func__);
++ }
++}
++
++void hwss_edp_power_control(
++ struct link_encoder *enc,
++ bool power_up)
++{
++ struct dc_context *ctx = enc->ctx;
++ struct dce_hwseq *hwseq = ctx->dc->hwseq;
++ struct bp_transmitter_control cntl = { 0 };
++ enum bp_result bp_result;
++
++
++ if (dal_graphics_object_id_get_connector_id(enc->connector)
++ != CONNECTOR_ID_EDP) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ if (power_up != is_panel_powered_on(hwseq)) {
++ /* Send VBIOS command to prompt eDP panel power */
++
++ dm_logger_write(ctx->logger, LOG_HW_RESUME_S3,
++ "%s: Panel Power action: %s\n",
++ __func__, (power_up ? "On":"Off"));
++
++ cntl.action = power_up ?
++ TRANSMITTER_CONTROL_POWER_ON :
++ TRANSMITTER_CONTROL_POWER_OFF;
++ cntl.transmitter = enc->transmitter;
++ cntl.connector_obj_id = enc->connector;
++ cntl.coherent = false;
++ cntl.lanes_number = LANE_COUNT_FOUR;
++ cntl.hpd_sel = enc->hpd_source;
++
++ bp_result = link_transmitter_control(ctx->dc_bios, &cntl);
++
++ if (bp_result != BP_RESULT_OK)
++ dm_logger_write(ctx->logger, LOG_ERROR,
++ "%s: Panel Power bp_result: %d\n",
++ __func__, bp_result);
++ } else {
++ dm_logger_write(ctx->logger, LOG_HW_RESUME_S3,
++ "%s: Skipping Panel Power action: %s\n",
++ __func__, (power_up ? "On":"Off"));
++ }
++
++ hwss_edp_wait_for_hpd_ready(enc, true);
++}
+
+ /*todo: cloned in stream enc, fix*/
+ /*
+ * @brief
+ * eDP only. Control the backlight of the eDP panel
+ */
+-void hwss_blacklight_control(
++void hwss_edp_backlight_control(
+ struct dc_link *link,
+ bool enable)
+ {
+@@ -828,6 +963,7 @@ void hwss_blacklight_control(
+ cntl.action = enable ?
+ TRANSMITTER_CONTROL_BACKLIGHT_ON :
+ TRANSMITTER_CONTROL_BACKLIGHT_OFF;
++
+ /*cntl.engine_id = ctx->engine;*/
+ cntl.transmitter = link->link_enc->transmitter;
+ cntl.connector_obj_id = link->link_enc->connector;
+@@ -846,7 +982,7 @@ void hwss_blacklight_control(
+ * Enable it in the future if necessary.
+ */
+ /* dc_service_sleep_in_milliseconds(50); */
+- link_transmitter_control(link, &cntl);
++ link_transmitter_control(link->dc->ctx->dc_bios, &cntl);
+ }
+
+ void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
+@@ -886,7 +1022,7 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
+ /* blank at encoder level */
+ if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
+ if (pipe_ctx->stream->sink->link->connector_signal == SIGNAL_TYPE_EDP)
+- hwss_blacklight_control(link, false);
++ hwss_edp_backlight_control(link, false);
+ pipe_ctx->stream_res.stream_enc->funcs->dp_blank(pipe_ctx->stream_res.stream_enc);
+ }
+ link->link_enc->funcs->connect_dig_be_to_fe(
+@@ -908,7 +1044,7 @@ void dce110_unblank_stream(struct pipe_ctx *pipe_ctx,
+ params.link_settings.link_rate = link_settings->link_rate;
+ pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(pipe_ctx->stream_res.stream_enc, &params);
+ if (link->connector_signal == SIGNAL_TYPE_EDP)
+- hwss_blacklight_control(link, true);
++ hwss_edp_backlight_control(link, true);
+ }
+
+
+@@ -2816,7 +2952,8 @@ static const struct hw_sequencer_funcs dce110_funcs = {
+ .wait_for_mpcc_disconnect = dce110_wait_for_mpcc_disconnect,
+ .ready_shared_resources = ready_shared_resources,
+ .optimize_shared_resources = optimize_shared_resources,
+- .backlight_control = hwss_blacklight_control
++ .edp_backlight_control = hwss_edp_backlight_control,
++ .edp_power_control = hwss_edp_power_control,
+ };
+
+ void dce110_hw_sequencer_construct(struct dc *dc)
+diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h
+index 3e95f7f..a1e964a 100644
+--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h
++++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h
+@@ -69,7 +69,11 @@ uint32_t dce110_get_min_vblank_time_us(const struct dc_state *context);
+
+ void dp_receiver_power_ctrl(struct dc_link *link, bool on);
+
+-void hwss_blacklight_control(
++void hwss_edp_power_control(
++ struct link_encoder *enc,
++ bool power_up);
++
++void hwss_edp_backlight_control(
+ struct dc_link *link,
+ bool enable);
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+index 014911e..efa3f6f 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+@@ -2903,7 +2903,8 @@ static const struct hw_sequencer_funcs dcn10_funcs = {
+ .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
+ .ready_shared_resources = ready_shared_resources,
+ .optimize_shared_resources = optimize_shared_resources,
+- .backlight_control = hwss_blacklight_control
++ .edp_backlight_control = hwss_edp_backlight_control,
++ .edp_power_control = hwss_edp_power_control
+ };
+
+
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
+index 6cd6bc7d..3d33bcd 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
+@@ -123,8 +123,6 @@ struct link_encoder_funcs {
+ bool exit_link_training_required);
+ void (*psr_program_secondary_packet)(struct link_encoder *enc,
+ unsigned int sdp_transmit_line_num_deadline);
+- void (*power_control) (struct link_encoder *enc,
+- bool power_up);
+ void (*connect_dig_be_to_fe)(struct link_encoder *enc,
+ enum engine_id engine,
+ bool connect);
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
+index 210874f..bf3ab5d 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
+@@ -28,6 +28,7 @@
+ #include "dc_types.h"
+ #include "clock_source.h"
+ #include "inc/hw/timing_generator.h"
++#include "inc/hw/link_encoder.h"
+ #include "core_status.h"
+
+ enum pipe_gating_control {
+@@ -176,8 +177,10 @@ struct hw_sequencer_funcs {
+
+ void (*ready_shared_resources)(struct dc *dc, struct dc_state *context);
+ void (*optimize_shared_resources)(struct dc *dc);
+-
+- void (*backlight_control)(
++ void (*edp_power_control)(
++ struct link_encoder *enc,
++ bool enable);
++ void (*edp_backlight_control)(
+ struct dc_link *link,
+ bool enable);
+ };
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h
+index f7994cf..f2b8c9a 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h
+@@ -40,6 +40,10 @@ enum dc_status core_link_write_dpcd(
+ const uint8_t *data,
+ uint32_t size);
+
++struct gpio *get_hpd_gpio(struct dc_bios *dcb,
++ struct graphics_object_id link_id,
++ struct gpio_service *gpio_service);
++
+ void dp_enable_link_phy(
+ struct dc_link *link,
+ enum signal_type signal,
+diff --git a/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c b/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c
+index 4f40534..88c2bde 100644
+--- a/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c
++++ b/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c
+@@ -73,10 +73,6 @@ static void virtual_link_encoder_update_mst_stream_allocation_table(
+ struct link_encoder *enc,
+ const struct link_mst_stream_allocation_table *table) {}
+
+-static void virtual_link_encoder_edp_power_control(
+- struct link_encoder *enc,
+- bool power_up) {}
+-
+ static void virtual_link_encoder_connect_dig_be_to_fe(
+ struct link_encoder *enc,
+ enum engine_id engine,
+@@ -102,7 +98,6 @@ static const struct link_encoder_funcs virtual_lnk_enc_funcs = {
+ .dp_set_phy_pattern = virtual_link_encoder_dp_set_phy_pattern,
+ .update_mst_stream_allocation_table =
+ virtual_link_encoder_update_mst_stream_allocation_table,
+- .power_control = virtual_link_encoder_edp_power_control,
+ .connect_dig_be_to_fe = virtual_link_encoder_connect_dig_be_to_fe,
+ .destroy = virtual_link_encoder_destroy
+ };
+--
+2.7.4
+