From 594b237b9a07e28d524b35a59dbff5bdc8de6b78 Mon Sep 17 00:00:00 2001 From: Alvin Lee Date: Wed, 10 Aug 2022 19:39:24 -0400 Subject: drm/amd/display: Add interface to track PHY state [Why] Sometimes pixel clock needs to remain active after transmitter disable. [How] Use update_phy_state to track PHY state after stream enable/disable and program pixel clock as needed. Reviewed-by: Alvin Lee Acked-by: Brian Chang Signed-off-by: Taimur Hassan Signed-off-by: Alvin Lee Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 18 ++++++++++-- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 12 ++++++-- drivers/gpu/drm/amd/display/dc/dc_link.h | 1 + .../amd/display/dc/dce110/dce110_hw_sequencer.c | 8 ++++-- drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c | 9 ++++-- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c | 9 ++++-- drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c | 32 ++++++++++++++++++++++ drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h | 3 ++ drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c | 1 + drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h | 6 ++++ drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h | 2 ++ 11 files changed, 88 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 5006263f8d56..ced09f875e58 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1180,7 +1180,11 @@ static void disable_vbios_mode_if_required( pipe->stream_res.pix_clk_params.requested_pix_clk_100hz; if (pix_clk_100hz != requested_pix_clk_100hz) { - core_link_disable_stream(pipe); + if (dc->hwss.update_phy_state) + dc->hwss.update_phy_state(dc->current_state, + pipe, TX_OFF_SYMCLK_OFF); + else + core_link_disable_stream(pipe); pipe->stream->dpms_off = false; } } @@ -3063,7 +3067,11 @@ static void commit_planes_do_stream_update(struct dc *dc, if (stream_update->dpms_off) { if (*stream_update->dpms_off) { - core_link_disable_stream(pipe_ctx); + if (dc->hwss.update_phy_state) + dc->hwss.update_phy_state(dc->current_state, + pipe_ctx, TX_OFF_SYMCLK_ON); + else + core_link_disable_stream(pipe_ctx); /* for dpms, keep acquired resources*/ if (pipe_ctx->stream_res.audio && !dc->debug.az_endpoint_mute_only) pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); @@ -3074,7 +3082,11 @@ static void commit_planes_do_stream_update(struct dc *dc, if (get_seamless_boot_stream_count(context) == 0) dc->hwss.prepare_bandwidth(dc, dc->current_state); - core_link_enable_stream(dc->current_state, pipe_ctx); + if (dc->hwss.update_phy_state) + dc->hwss.update_phy_state(dc->current_state, + pipe_ctx, TX_ON_SYMCLK_ON); + else + core_link_enable_stream(dc->current_state, pipe_ctx); } } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 48dad093ae8b..f92bbc86772e 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -4519,7 +4519,11 @@ void dc_link_dp_handle_link_loss(struct dc_link *link) pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx && pipe_ctx->stream && !pipe_ctx->stream->dpms_off && pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe) { - core_link_disable_stream(pipe_ctx); + if (link->dc->hwss.update_phy_state) + link->dc->hwss.update_phy_state(link->dc->current_state, + pipe_ctx, TX_OFF_SYMCLK_OFF); + else + core_link_disable_stream(pipe_ctx); } } @@ -4527,7 +4531,11 @@ void dc_link_dp_handle_link_loss(struct dc_link *link) pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx && pipe_ctx->stream && !pipe_ctx->stream->dpms_off && pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe) { - core_link_enable_stream(link->dc->current_state, pipe_ctx); + if (link->dc->hwss.update_phy_state) + link->dc->hwss.update_phy_state(link->dc->current_state, + pipe_ctx, TX_ON_SYMCLK_ON); + else + core_link_enable_stream(link->dc->current_state, pipe_ctx); } } } diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 9544abf75e84..b18efe988830 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -232,6 +232,7 @@ struct dc_link { struct gpio *hpd_gpio; enum dc_link_fec_state fec_state; + enum phy_state phy_state; }; const struct dc_link_status *dc_link_get_status(const struct dc_link *dc_link); 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 38a67051d470..801206aed63a 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 @@ -1577,8 +1577,12 @@ static enum dc_status apply_single_controller_ctx_to_hw( if (dc_is_dp_signal(pipe_ctx->stream->signal)) dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG); - if (!stream->dpms_off) - core_link_enable_stream(context, pipe_ctx); + if (!stream->dpms_off) { + if (dc->hwss.update_phy_state) + dc->hwss.update_phy_state(context, pipe_ctx, TX_ON_SYMCLK_ON); + else + core_link_enable_stream(context, pipe_ctx); + } /* DCN3.1 FPGA Workaround * Need to enable HPO DP Stream Encoder before setting OTG master enable. diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index 884fa060f375..cf439ed270de 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -2361,9 +2361,12 @@ static void dcn20_reset_back_end_for_pipe( * screen only, the dpms_off would be true but * VBIOS lit up eDP, so check link status too. */ - if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) - core_link_disable_stream(pipe_ctx); - else if (pipe_ctx->stream_res.audio) + if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) { + if (dc->hwss.update_phy_state) + dc->hwss.update_phy_state(dc->current_state, pipe_ctx, TX_OFF_SYMCLK_OFF); + else + core_link_disable_stream(pipe_ctx); + } else if (pipe_ctx->stream_res.audio) dc->hwss.disable_audio_stream(pipe_ctx); /* free acquired resources */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c index 1ed1404e969d..8d83b611507a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c @@ -553,9 +553,12 @@ static void dcn31_reset_back_end_for_pipe( * screen only, the dpms_off would be true but * VBIOS lit up eDP, so check link status too. */ - if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) - core_link_disable_stream(pipe_ctx); - else if (pipe_ctx->stream_res.audio) + if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) { + if (dc->hwss.update_phy_state) + dc->hwss.update_phy_state(dc->current_state, pipe_ctx, TX_OFF_SYMCLK_OFF); + else + core_link_disable_stream(pipe_ctx); + } else if (pipe_ctx->stream_res.audio) dc->hwss.disable_audio_stream(pipe_ctx); /* free acquired resources */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c index d1249fe1e412..3b1c6603ae0c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c @@ -1218,3 +1218,35 @@ bool dcn32_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx) return true; return false; } + +void dcn32_update_phy_state(struct dc_state *state, struct pipe_ctx *pipe_ctx, + enum phy_state target_state) +{ + enum phy_state current_state = pipe_ctx->stream->link->phy_state; + + if (current_state == target_state) { + BREAK_TO_DEBUGGER(); + return; + } + + if (target_state == TX_OFF_SYMCLK_OFF) { + core_link_disable_stream(pipe_ctx); + pipe_ctx->stream->link->phy_state = TX_OFF_SYMCLK_OFF; + } else if (target_state == TX_ON_SYMCLK_ON) { + core_link_enable_stream(state, pipe_ctx); + pipe_ctx->stream->link->phy_state = TX_ON_SYMCLK_ON; + } else if (target_state == TX_OFF_SYMCLK_ON) { + if (current_state == TX_ON_SYMCLK_ON) { + core_link_disable_stream(pipe_ctx); + pipe_ctx->stream->link->phy_state = TX_OFF_SYMCLK_OFF; + } + + pipe_ctx->clock_source->funcs->program_pix_clk( + pipe_ctx->clock_source, + &pipe_ctx->stream_res.pix_clk_params, + dp_get_link_encoding_format(&pipe_ctx->link_config.dp_link_settings), + &pipe_ctx->pll_settings); + pipe_ctx->stream->link->phy_state = TX_OFF_SYMCLK_ON; + } else + BREAK_TO_DEBUGGER(); +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h index 083f3aeb54f0..221e31144d50 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h @@ -84,4 +84,7 @@ void dcn32_unblank_stream(struct pipe_ctx *pipe_ctx, bool dcn32_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx); +void dcn32_update_phy_state(struct dc_state *state, struct pipe_ctx *pipe_ctx, + enum phy_state target_state); + #endif /* __DC_HWSS_DCN32_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c index c279a25ea293..28d220218133 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c @@ -104,6 +104,7 @@ static const struct hw_sequencer_funcs dcn32_funcs = { .commit_subvp_config = dcn32_commit_subvp_config, .subvp_pipe_control_lock = dcn32_subvp_pipe_control_lock, .update_visual_confirm_color = dcn20_update_visual_confirm_color, + .update_phy_state = dcn32_update_phy_state, }; static const struct hwseq_private_funcs dcn32_private_funcs = { diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h index d89bd55f110f..437b64e87377 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h @@ -268,6 +268,12 @@ enum dc_lut_mode { LUT_RAM_B }; +enum phy_state { + TX_OFF_SYMCLK_OFF, + TX_ON_SYMCLK_ON, + TX_OFF_SYMCLK_ON +}; + /** * speakersToChannels * 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 ccb3c719fc4d..a4e02b0ace24 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -245,6 +245,8 @@ struct hw_sequencer_funcs { struct tg_color *color, int mpcc_id); + void (*update_phy_state)(struct dc_state *state, struct pipe_ctx *pipe_ctx, enum phy_state target_state); + void (*commit_subvp_config)(struct dc *dc, struct dc_state *context); void (*subvp_pipe_control_lock)(struct dc *dc, struct dc_state *context, -- cgit