Commit 61f14c5b authored by Lucy Li's avatar Lucy Li Committed by Alex Deucher

drm/amd/display: Disable link before reenable

[Why]
Black screen seen after display is disabled then re-enabled.
Caused by difference in link settings when
switching between different resolutions.

[How]
In PnP case, or whenever the display is
still enabled but the driver is unloaded,
disable link before re-enabling with new link settings.
Signed-off-by: default avatarLucy Li <lucy.li@amd.com>
Reviewed-by: default avatarAnthony Koo <Anthony.Koo@amd.com>
Acked-by: default avatarLeo Li <sunpeng.li@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 832aa63b
...@@ -1511,15 +1511,6 @@ static enum dc_status enable_link_dp( ...@@ -1511,15 +1511,6 @@ static enum dc_status enable_link_dp(
decide_link_settings(stream, &link_settings); decide_link_settings(stream, &link_settings);
if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP) { if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP) {
/* If link settings are different than current and link already enabled
* then need to disable before programming to new rate.
*/
if (link->link_status.link_active &&
(link->cur_link_settings.lane_count != link_settings.lane_count ||
link->cur_link_settings.link_rate != link_settings.link_rate)) {
dp_disable_link_phy(link, pipe_ctx->stream->signal);
}
/*in case it is not on*/ /*in case it is not on*/
link->dc->hwss.edp_power_control(link, true); link->dc->hwss.edp_power_control(link, true);
link->dc->hwss.edp_wait_for_hpd_ready(link, true); link->dc->hwss.edp_wait_for_hpd_ready(link, true);
...@@ -2039,6 +2030,45 @@ static void write_i2c_redriver_setting( ...@@ -2039,6 +2030,45 @@ static void write_i2c_redriver_setting(
ASSERT(i2c_success); ASSERT(i2c_success);
} }
static void disable_link(struct dc_link *link, enum signal_type signal)
{
/*
* TODO: implement call for dp_set_hw_test_pattern
* it is needed for compliance testing
*/
/* Here we need to specify that encoder output settings
* need to be calculated as for the set mode,
* it will lead to querying dynamic link capabilities
* which should be done before enable output
*/
if (dc_is_dp_signal(signal)) {
/* SST DP, eDP */
if (dc_is_dp_sst_signal(signal))
dp_disable_link_phy(link, signal);
else
dp_disable_link_phy_mst(link, signal);
if (dc_is_dp_sst_signal(signal) ||
link->mst_stream_alloc_table.stream_count == 0) {
dp_set_fec_enable(link, false);
dp_set_fec_ready(link, false);
}
} else {
if (signal != SIGNAL_TYPE_VIRTUAL)
link->link_enc->funcs->disable_output(link->link_enc, signal);
}
if (signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
/* MST disable link only when no stream use the link */
if (link->mst_stream_alloc_table.stream_count <= 0)
link->link_status.link_active = false;
} else {
link->link_status.link_active = false;
}
}
static void enable_link_hdmi(struct pipe_ctx *pipe_ctx) static void enable_link_hdmi(struct pipe_ctx *pipe_ctx)
{ {
struct dc_stream_state *stream = pipe_ctx->stream; struct dc_stream_state *stream = pipe_ctx->stream;
...@@ -2123,6 +2153,19 @@ static enum dc_status enable_link( ...@@ -2123,6 +2153,19 @@ static enum dc_status enable_link(
struct pipe_ctx *pipe_ctx) struct pipe_ctx *pipe_ctx)
{ {
enum dc_status status = DC_ERROR_UNEXPECTED; enum dc_status status = DC_ERROR_UNEXPECTED;
struct dc_stream_state *stream = pipe_ctx->stream;
struct dc_link *link = stream->link;
/* There's some scenarios where driver is unloaded with display
* still enabled. When driver is reloaded, it may cause a display
* to not light up if there is a mismatch between old and new
* link settings. Need to call disable first before enabling at
* new link settings.
*/
if (link->link_status.link_active) {
disable_link(link, pipe_ctx->stream->signal);
}
switch (pipe_ctx->stream->signal) { switch (pipe_ctx->stream->signal) {
case SIGNAL_TYPE_DISPLAY_PORT: case SIGNAL_TYPE_DISPLAY_PORT:
status = enable_link_dp(state, pipe_ctx); status = enable_link_dp(state, pipe_ctx);
...@@ -2157,44 +2200,6 @@ static enum dc_status enable_link( ...@@ -2157,44 +2200,6 @@ static enum dc_status enable_link(
return status; return status;
} }
static void disable_link(struct dc_link *link, enum signal_type signal)
{
/*
* TODO: implement call for dp_set_hw_test_pattern
* it is needed for compliance testing
*/
/* here we need to specify that encoder output settings
* need to be calculated as for the set mode,
* it will lead to querying dynamic link capabilities
* which should be done before enable output */
if (dc_is_dp_signal(signal)) {
/* SST DP, eDP */
if (dc_is_dp_sst_signal(signal))
dp_disable_link_phy(link, signal);
else
dp_disable_link_phy_mst(link, signal);
if (dc_is_dp_sst_signal(signal) ||
link->mst_stream_alloc_table.stream_count == 0) {
dp_set_fec_enable(link, false);
dp_set_fec_ready(link, false);
}
} else {
if (signal != SIGNAL_TYPE_VIRTUAL)
link->link_enc->funcs->disable_output(link->link_enc, signal);
}
if (signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
/* MST disable link only when no stream use the link */
if (link->mst_stream_alloc_table.stream_count <= 0)
link->link_status.link_active = false;
} else {
link->link_status.link_active = false;
}
}
static uint32_t get_timing_pixel_clock_100hz(const struct dc_crtc_timing *timing) static uint32_t get_timing_pixel_clock_100hz(const struct dc_crtc_timing *timing)
{ {
......
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