Commit 87401969 authored by Andrew Jiang's avatar Andrew Jiang Committed by Alex Deucher

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: default avatarAndrew Jiang <Andrew.Jiang@amd.com>
Reviewed-by: default avatarTony Cheng <Tony.Cheng@amd.com>
Acked-by: default avatarHarry Wentland <Harry.Wentland@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent b87d78d6
...@@ -78,14 +78,15 @@ static void destruct(struct dc_link *link) ...@@ -78,14 +78,15 @@ static void destruct(struct dc_link *link)
dc_sink_release(link->remote_sinks[i]); 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; enum bp_result bp_result;
struct dc_bios *dcb = link->ctx->dc_bios;
struct graphics_object_hpd_info hpd_info; struct graphics_object_hpd_info hpd_info;
struct gpio_pin_info pin_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; return NULL;
bp_result = dcb->funcs->get_gpio_pin_info(dcb, bp_result = dcb->funcs->get_gpio_pin_info(dcb,
...@@ -97,7 +98,7 @@ static struct gpio *get_hpd_gpio(const struct dc_link *link) ...@@ -97,7 +98,7 @@ static struct gpio *get_hpd_gpio(const struct dc_link *link)
} }
return dal_gpio_service_create_irq( return dal_gpio_service_create_irq(
link->ctx->gpio_service, gpio_service,
pin_info.offset, pin_info.offset,
pin_info.mask); pin_info.mask);
} }
...@@ -153,7 +154,7 @@ static bool program_hpd_filter( ...@@ -153,7 +154,7 @@ static bool program_hpd_filter(
} }
/* Obtain HPD handle */ /* 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) if (!hpd)
return result; return result;
...@@ -186,7 +187,7 @@ static bool detect_sink(struct dc_link *link, enum dc_connection_type *type) ...@@ -186,7 +187,7 @@ static bool detect_sink(struct dc_link *link, enum dc_connection_type *type)
struct gpio *hpd_pin; struct gpio *hpd_pin;
/* todo: may need to lock gpio access */ /* 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) if (hpd_pin == NULL)
goto hpd_gpio_failure; goto hpd_gpio_failure;
...@@ -795,7 +796,7 @@ static enum hpd_source_id get_hpd_line( ...@@ -795,7 +796,7 @@ static enum hpd_source_id get_hpd_line(
struct gpio *hpd; struct gpio *hpd;
enum hpd_source_id hpd_id = HPD_SOURCEID_UNKNOWN; 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) { if (hpd) {
switch (dal_irq_get_source(hpd)) { switch (dal_irq_get_source(hpd)) {
...@@ -965,7 +966,7 @@ static bool construct( ...@@ -965,7 +966,7 @@ static bool construct(
goto create_fail; 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) if (hpd_gpio != NULL)
link->irq_source_hpd = dal_irq_get_source(hpd_gpio); link->irq_source_hpd = dal_irq_get_source(hpd_gpio);
......
...@@ -89,12 +89,12 @@ void dp_enable_link_phy( ...@@ -89,12 +89,12 @@ void dp_enable_link_phy(
if (dc_is_dp_sst_signal(signal)) { if (dc_is_dp_sst_signal(signal)) {
if (signal == SIGNAL_TYPE_EDP) { 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->funcs->enable_dp_output(
link_enc, link_enc,
link_settings, link_settings,
clock_source); clock_source);
link->dc->hwss.backlight_control(link, true); link->dc->hwss.edp_backlight_control(link, true);
} else } else
link_enc->funcs->enable_dp_output( link_enc->funcs->enable_dp_output(
link_enc, link_enc,
...@@ -138,10 +138,10 @@ void dp_disable_link_phy(struct dc_link *link, enum signal_type signal) ...@@ -138,10 +138,10 @@ void dp_disable_link_phy(struct dc_link *link, enum signal_type signal)
dp_receiver_power_ctrl(link, false); dp_receiver_power_ctrl(link, false);
if (signal == SIGNAL_TYPE_EDP) { 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); edp_receiver_ready_T9(link);
link->link_enc->funcs->disable_output(link->link_enc, signal, 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 } else
link->link_enc->funcs->disable_output(link->link_enc, signal, link); link->link_enc->funcs->disable_output(link->link_enc, signal, link);
......
...@@ -391,23 +391,27 @@ struct dce_hwseq_registers { ...@@ -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_, V_UPDATE_LOCK, BLND_DCP_GRPH_SURF_V_UPDATE_LOCK, mask_sh),\
HWS_SF(BLND_, CONTROL, BLND_MODE, mask_sh),\ HWS_SF(BLND_, CONTROL, BLND_MODE, 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),\
HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_) HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_)
#define HWSEQ_DCE10_MASK_SH_LIST(mask_sh)\ #define HWSEQ_DCE10_MASK_SH_LIST(mask_sh)\
HWSEQ_DCEF_MASK_SH_LIST(mask_sh, DCFE_),\ HWSEQ_DCEF_MASK_SH_LIST(mask_sh, DCFE_),\
HWSEQ_BLND_MASK_SH_LIST(mask_sh, BLND_),\ HWSEQ_BLND_MASK_SH_LIST(mask_sh, BLND_),\
HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_), \ 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)\ #define HWSEQ_DCE11_MASK_SH_LIST(mask_sh)\
HWSEQ_DCE10_MASK_SH_LIST(mask_sh),\ HWSEQ_DCE10_MASK_SH_LIST(mask_sh),\
SF(DCFEV_CLOCK_CONTROL, DCFEV_CLOCK_ENABLE, mask_sh),\ SF(DCFEV_CLOCK_CONTROL, DCFEV_CLOCK_ENABLE, 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),\
HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_) HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_)
#define HWSEQ_DCE112_MASK_SH_LIST(mask_sh)\ #define HWSEQ_DCE112_MASK_SH_LIST(mask_sh)\
HWSEQ_DCE10_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_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_) HWSEQ_PHYPLL_MASK_SH_LIST(mask_sh, CRTC0_)
#define HWSEQ_GFX9_DCHUB_MASK_SH_LIST(mask_sh)\ #define HWSEQ_GFX9_DCHUB_MASK_SH_LIST(mask_sh)\
...@@ -416,7 +420,8 @@ struct dce_hwseq_registers { ...@@ -416,7 +420,8 @@ struct dce_hwseq_registers {
SF(DCHUB_AGP_BASE, AGP_BASE, mask_sh),\ SF(DCHUB_AGP_BASE, AGP_BASE, mask_sh),\
SF(DCHUB_AGP_BOT, AGP_BOT, mask_sh),\ SF(DCHUB_AGP_BOT, AGP_BOT, mask_sh),\
SF(DCHUB_AGP_TOP, AGP_TOP, 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)\ #define HWSEQ_DCE12_MASK_SH_LIST(mask_sh)\
HWSEQ_DCEF_MASK_SH_LIST(mask_sh, DCFE0_DCFE_),\ HWSEQ_DCEF_MASK_SH_LIST(mask_sh, DCFE0_DCFE_),\
...@@ -424,7 +429,8 @@ struct dce_hwseq_registers { ...@@ -424,7 +429,8 @@ struct dce_hwseq_registers {
HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_),\ HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_),\
HWSEQ_PHYPLL_MASK_SH_LIST(mask_sh, CRTC0_),\ HWSEQ_PHYPLL_MASK_SH_LIST(mask_sh, CRTC0_),\
HWSEQ_GFX9_DCHUB_MASK_SH_LIST(mask_sh), \ 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)\ #define HWSEQ_DCN_MASK_SH_LIST(mask_sh)\
HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, OTG0_),\ HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, OTG0_),\
...@@ -489,7 +495,8 @@ struct dce_hwseq_registers { ...@@ -489,7 +495,8 @@ struct dce_hwseq_registers {
HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \ HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \
HWS_SF(, DOMAIN7_PG_STATUS, DOMAIN7_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(, 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) \ #define HWSEQ_REG_FIELD_LIST(type) \
type DCFE_CLOCK_ENABLE; \ type DCFE_CLOCK_ENABLE; \
...@@ -520,7 +527,8 @@ struct dce_hwseq_registers { ...@@ -520,7 +527,8 @@ struct dce_hwseq_registers {
type LOGICAL_ADDR; \ type LOGICAL_ADDR; \
type ENABLE_L1_TLB;\ type ENABLE_L1_TLB;\
type SYSTEM_ACCESS_MODE;\ type SYSTEM_ACCESS_MODE;\
type LVTMA_BLON; type LVTMA_BLON;\
type LVTMA_PWRSEQ_TARGET_STATE_R;
#define HWSEQ_DCN_REG_FIELD_LIST(type) \ #define HWSEQ_DCN_REG_FIELD_LIST(type) \
type VUPDATE_NO_LOCK_EVENT_CLEAR; \ type VUPDATE_NO_LOCK_EVENT_CLEAR; \
......
...@@ -82,13 +82,6 @@ ...@@ -82,13 +82,6 @@
#define DCE110_DIG_FE_SOURCE_SELECT_DIGF 0x20 #define DCE110_DIG_FE_SOURCE_SELECT_DIGF 0x20
#define DCE110_DIG_FE_SOURCE_SELECT_DIGG 0x40 #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 */ /* Minimum pixel clock, in KHz. For TMDS signal is 25.00 MHz */
#define TMDS_MIN_PIXEL_CLOCK 25000 #define TMDS_MIN_PIXEL_CLOCK 25000
/* Maximum pixel clock, in KHz. For TMDS signal is 165.00 MHz */ /* 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 = { ...@@ -122,7 +115,6 @@ static const struct link_encoder_funcs dce110_lnk_enc_funcs = {
.psr_program_dp_dphy_fast_training = .psr_program_dp_dphy_fast_training =
dce110_psr_program_dp_dphy_fast_training, dce110_psr_program_dp_dphy_fast_training,
.psr_program_secondary_packet = dce110_psr_program_secondary_packet, .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, .connect_dig_be_to_fe = dce110_link_encoder_connect_dig_be_to_fe,
.enable_hpd = dce110_link_encoder_enable_hpd, .enable_hpd = dce110_link_encoder_enable_hpd,
.disable_hpd = dce110_link_encoder_disable_hpd, .disable_hpd = dce110_link_encoder_disable_hpd,
...@@ -492,165 +484,6 @@ static void configure_encoder( ...@@ -492,165 +484,6 @@ static void configure_encoder(
REG_UPDATE(DP_DPHY_SCRAM_CNTL, DPHY_SCRAMBLER_ADVANCE, 1); 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( static void aux_initialize(
struct dce110_link_encoder *enc110) struct dce110_link_encoder *enc110)
{ {
...@@ -1018,7 +851,7 @@ void dce110_link_encoder_hw_init( ...@@ -1018,7 +851,7 @@ void dce110_link_encoder_hw_init(
ASSERT(result == BP_RESULT_OK); ASSERT(result == BP_RESULT_OK);
} else if (enc110->base.connector.id == CONNECTOR_ID_EDP) { } 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); aux_initialize(enc110);
...@@ -1218,7 +1051,7 @@ void dce110_link_encoder_disable_output( ...@@ -1218,7 +1051,7 @@ void dce110_link_encoder_disable_output(
return; return;
} }
if (enc110->base.connector.id == CONNECTOR_ID_EDP) 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. /* Power-down RX and disable GPU PHY should be paired.
* Disabling PHY without powering down RX may cause * Disabling PHY without powering down RX may cause
* symbol lock loss, on which we will get DP Sink interrupt. */ * symbol lock loss, on which we will get DP Sink interrupt. */
......
...@@ -114,10 +114,6 @@ struct dce110_link_enc_hpd_registers { ...@@ -114,10 +114,6 @@ struct dce110_link_enc_hpd_registers {
}; };
struct dce110_link_enc_registers { struct dce110_link_enc_registers {
/* Backlight registers */
uint32_t LVTMA_PWRSEQ_CNTL;
uint32_t LVTMA_PWRSEQ_STATE;
/* DMCU registers */ /* DMCU registers */
uint32_t MASTER_COMM_DATA_REG1; uint32_t MASTER_COMM_DATA_REG1;
uint32_t MASTER_COMM_DATA_REG2; uint32_t MASTER_COMM_DATA_REG2;
...@@ -250,10 +246,6 @@ void dce110_link_encoder_update_mst_stream_allocation_table( ...@@ -250,10 +246,6 @@ void dce110_link_encoder_update_mst_stream_allocation_table(
struct link_encoder *enc, struct link_encoder *enc,
const struct link_mst_stream_allocation_table *table); 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( void dce110_link_encoder_connect_dig_be_to_fe(
struct link_encoder *enc, struct link_encoder *enc,
enum engine_id engine, enum engine_id engine,
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "dce110_hw_sequencer.h" #include "dce110_hw_sequencer.h"
#include "dce110_timing_generator.h" #include "dce110_timing_generator.h"
#include "dce/dce_hwseq.h" #include "dce/dce_hwseq.h"
#include "gpio_service_interface.h"
#ifdef ENABLE_FBC #ifdef ENABLE_FBC
#include "dce110_compressor.h" #include "dce110_compressor.h"
...@@ -45,10 +46,10 @@ ...@@ -45,10 +46,10 @@
#include "transform.h" #include "transform.h"
#include "stream_encoder.h" #include "stream_encoder.h"
#include "link_encoder.h" #include "link_encoder.h"
#include "link_hwss.h"
#include "clock_source.h" #include "clock_source.h"
#include "abm.h" #include "abm.h"
#include "audio.h" #include "audio.h"
#include "dce/dce_hwseq.h"
#include "reg_helper.h" #include "reg_helper.h"
/* include DCE11 register header files */ /* include DCE11 register header files */
...@@ -56,6 +57,15 @@ ...@@ -56,6 +57,15 @@
#include "dce/dce_11_0_sh_mask.h" #include "dce/dce_11_0_sh_mask.h"
#include "custom_float.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 \ #define CTX \
hws->ctx hws->ctx
#define REG(reg)\ #define REG(reg)\
...@@ -780,25 +790,150 @@ static bool is_panel_backlight_on(struct dce_hwseq *hws) ...@@ -780,25 +790,150 @@ static bool is_panel_backlight_on(struct dce_hwseq *hws)
return value; 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( static enum bp_result link_transmitter_control(
struct dc_link *link, struct dc_bios *bios,
struct bp_transmitter_control *cntl) struct bp_transmitter_control *cntl)
{ {
enum bp_result result; 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; 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*/ /*todo: cloned in stream enc, fix*/
/* /*
* @brief * @brief
* eDP only. Control the backlight of the eDP panel * eDP only. Control the backlight of the eDP panel
*/ */
void hwss_blacklight_control( void hwss_edp_backlight_control(
struct dc_link *link, struct dc_link *link,
bool enable) bool enable)
{ {
...@@ -828,6 +963,7 @@ void hwss_blacklight_control( ...@@ -828,6 +963,7 @@ void hwss_blacklight_control(
cntl.action = enable ? cntl.action = enable ?
TRANSMITTER_CONTROL_BACKLIGHT_ON : TRANSMITTER_CONTROL_BACKLIGHT_ON :
TRANSMITTER_CONTROL_BACKLIGHT_OFF; TRANSMITTER_CONTROL_BACKLIGHT_OFF;
/*cntl.engine_id = ctx->engine;*/ /*cntl.engine_id = ctx->engine;*/
cntl.transmitter = link->link_enc->transmitter; cntl.transmitter = link->link_enc->transmitter;
cntl.connector_obj_id = link->link_enc->connector; cntl.connector_obj_id = link->link_enc->connector;
...@@ -846,7 +982,7 @@ void hwss_blacklight_control( ...@@ -846,7 +982,7 @@ void hwss_blacklight_control(
* Enable it in the future if necessary. * Enable it in the future if necessary.
*/ */
/* dc_service_sleep_in_milliseconds(50); */ /* 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) void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
...@@ -886,7 +1022,7 @@ 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 */ /* blank at encoder level */
if (dc_is_dp_signal(pipe_ctx->stream->signal)) { if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
if (pipe_ctx->stream->sink->link->connector_signal == SIGNAL_TYPE_EDP) 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); pipe_ctx->stream_res.stream_enc->funcs->dp_blank(pipe_ctx->stream_res.stream_enc);
} }
link->link_enc->funcs->connect_dig_be_to_fe( link->link_enc->funcs->connect_dig_be_to_fe(
...@@ -908,7 +1044,7 @@ void dce110_unblank_stream(struct pipe_ctx *pipe_ctx, ...@@ -908,7 +1044,7 @@ void dce110_unblank_stream(struct pipe_ctx *pipe_ctx,
params.link_settings.link_rate = link_settings->link_rate; 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); pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(pipe_ctx->stream_res.stream_enc, &params);
if (link->connector_signal == SIGNAL_TYPE_EDP) if (link->connector_signal == SIGNAL_TYPE_EDP)
hwss_blacklight_control(link, true); hwss_edp_backlight_control(link, true);
} }
...@@ -2821,7 +2957,8 @@ static const struct hw_sequencer_funcs dce110_funcs = { ...@@ -2821,7 +2957,8 @@ static const struct hw_sequencer_funcs dce110_funcs = {
.wait_for_mpcc_disconnect = dce110_wait_for_mpcc_disconnect, .wait_for_mpcc_disconnect = dce110_wait_for_mpcc_disconnect,
.ready_shared_resources = ready_shared_resources, .ready_shared_resources = ready_shared_resources,
.optimize_shared_resources = optimize_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) void dce110_hw_sequencer_construct(struct dc *dc)
......
...@@ -69,7 +69,11 @@ uint32_t dce110_get_min_vblank_time_us(const struct dc_state *context); ...@@ -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 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, struct dc_link *link,
bool enable); bool enable);
......
...@@ -2903,7 +2903,8 @@ static const struct hw_sequencer_funcs dcn10_funcs = { ...@@ -2903,7 +2903,8 @@ static const struct hw_sequencer_funcs dcn10_funcs = {
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
.ready_shared_resources = ready_shared_resources, .ready_shared_resources = ready_shared_resources,
.optimize_shared_resources = optimize_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
}; };
......
...@@ -123,8 +123,6 @@ struct link_encoder_funcs { ...@@ -123,8 +123,6 @@ struct link_encoder_funcs {
bool exit_link_training_required); bool exit_link_training_required);
void (*psr_program_secondary_packet)(struct link_encoder *enc, void (*psr_program_secondary_packet)(struct link_encoder *enc,
unsigned int sdp_transmit_line_num_deadline); 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, void (*connect_dig_be_to_fe)(struct link_encoder *enc,
enum engine_id engine, enum engine_id engine,
bool connect); bool connect);
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "dc_types.h" #include "dc_types.h"
#include "clock_source.h" #include "clock_source.h"
#include "inc/hw/timing_generator.h" #include "inc/hw/timing_generator.h"
#include "inc/hw/link_encoder.h"
#include "core_status.h" #include "core_status.h"
enum pipe_gating_control { enum pipe_gating_control {
...@@ -176,8 +177,10 @@ struct hw_sequencer_funcs { ...@@ -176,8 +177,10 @@ struct hw_sequencer_funcs {
void (*ready_shared_resources)(struct dc *dc, struct dc_state *context); void (*ready_shared_resources)(struct dc *dc, struct dc_state *context);
void (*optimize_shared_resources)(struct dc *dc); void (*optimize_shared_resources)(struct dc *dc);
void (*edp_power_control)(
void (*backlight_control)( struct link_encoder *enc,
bool enable);
void (*edp_backlight_control)(
struct dc_link *link, struct dc_link *link,
bool enable); bool enable);
}; };
......
...@@ -40,6 +40,10 @@ enum dc_status core_link_write_dpcd( ...@@ -40,6 +40,10 @@ enum dc_status core_link_write_dpcd(
const uint8_t *data, const uint8_t *data,
uint32_t size); 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( void dp_enable_link_phy(
struct dc_link *link, struct dc_link *link,
enum signal_type signal, enum signal_type signal,
......
...@@ -73,10 +73,6 @@ static void virtual_link_encoder_update_mst_stream_allocation_table( ...@@ -73,10 +73,6 @@ static void virtual_link_encoder_update_mst_stream_allocation_table(
struct link_encoder *enc, struct link_encoder *enc,
const struct link_mst_stream_allocation_table *table) {} 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( static void virtual_link_encoder_connect_dig_be_to_fe(
struct link_encoder *enc, struct link_encoder *enc,
enum engine_id engine, enum engine_id engine,
...@@ -102,7 +98,6 @@ static const struct link_encoder_funcs virtual_lnk_enc_funcs = { ...@@ -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, .dp_set_phy_pattern = virtual_link_encoder_dp_set_phy_pattern,
.update_mst_stream_allocation_table = .update_mst_stream_allocation_table =
virtual_link_encoder_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, .connect_dig_be_to_fe = virtual_link_encoder_connect_dig_be_to_fe,
.destroy = virtual_link_encoder_destroy .destroy = virtual_link_encoder_destroy
}; };
......
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