drm/amd/display: Fix Link Override Sequencing When Switching Between DIO/HPO
[WHY] When performing certain link maintenance compliance tests or forcing link settings, changing between 128b/132b and 8b/10b rates no longer works on some ASICs. Some rate divider updates only occur when we set timings or validate state, which is not performed currently when toggling DPMS to change rates. [HOW] Re-calculate dividers and reprogram audio when switching between DIO and HPO through DP compliance/escape code path. Add OTG disable/re-enable so we don't touch the clock while OTG is active. Acquire dcLock before forcing link settings to avoid thread synchronization errors due to added programming in escape code path and potential HPD interrupts. Reviewed-by: George Shen <george.shen@amd.com> Signed-off-by: Michael Strauss <michael.strauss@amd.com> Signed-off-by: Mike Katsnelson <mike.katsnelson@amd.com> Signed-off-by: Ray Wu <ray.wu@amd.com> Tested-by: Daniel Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>pull/1309/head
parent
51496c7737
commit
9c6669c2e2
|
|
@ -1381,7 +1381,7 @@ static void populate_audio_dp_link_info(
|
|||
}
|
||||
}
|
||||
|
||||
static void build_audio_output(
|
||||
void build_audio_output(
|
||||
struct dc_state *state,
|
||||
const struct pipe_ctx *pipe_ctx,
|
||||
struct audio_output *audio_output)
|
||||
|
|
|
|||
|
|
@ -110,5 +110,9 @@ void dce110_enable_dp_link_output(
|
|||
enum signal_type signal,
|
||||
enum clock_source_id clock_source,
|
||||
const struct dc_link_settings *link_settings);
|
||||
void build_audio_output(
|
||||
struct dc_state *state,
|
||||
const struct pipe_ctx *pipe_ctx,
|
||||
struct audio_output *audio_output);
|
||||
#endif /* __DC_HWSS_DCE110_H__ */
|
||||
|
||||
|
|
|
|||
|
|
@ -223,6 +223,11 @@ struct resource_funcs {
|
|||
const struct dc_stream_state *stream);
|
||||
bool (*program_mcache_pipe_config)(struct dc_state *context,
|
||||
const struct dc_mcache_params *mcache_params);
|
||||
enum dc_status (*update_dc_state_for_encoder_switch)(struct dc_link *link,
|
||||
struct dc_link_settings *link_setting,
|
||||
uint8_t pipe_count,
|
||||
struct pipe_ctx *pipes,
|
||||
struct audio_output *audio_output);
|
||||
};
|
||||
|
||||
struct audio_support{
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "dm_helpers.h"
|
||||
#include "dc_dmub_srv.h"
|
||||
#include "dce/dmub_hw_lock_mgr.h"
|
||||
#include "clk_mgr.h"
|
||||
|
||||
#define DC_LOGGER \
|
||||
link->ctx->logger
|
||||
|
|
@ -67,10 +68,17 @@ static void dp_retrain_link_dp_test(struct dc_link *link,
|
|||
{
|
||||
struct pipe_ctx *pipes[MAX_PIPES];
|
||||
struct dc_state *state = link->dc->current_state;
|
||||
struct dc_stream_update stream_update = { 0 };
|
||||
bool dpms_off = false;
|
||||
bool needs_divider_update = false;
|
||||
bool was_hpo_acquired = resource_is_hpo_acquired(link->dc->current_state);
|
||||
bool is_hpo_acquired;
|
||||
uint8_t count;
|
||||
int i;
|
||||
struct audio_output audio_output[MAX_PIPES];
|
||||
|
||||
needs_divider_update = (link->dc->link_srv->dp_get_encoding_format(link_setting) !=
|
||||
link->dc->link_srv->dp_get_encoding_format((const struct dc_link_settings *) &link->cur_link_settings));
|
||||
|
||||
udelay(100);
|
||||
|
||||
|
|
@ -83,16 +91,59 @@ static void dp_retrain_link_dp_test(struct dc_link *link,
|
|||
link->dc,
|
||||
state,
|
||||
pipes[i]);
|
||||
|
||||
// Disable OTG and re-enable after updating clocks
|
||||
pipes[i]->stream_res.tg->funcs->disable_crtc(pipes[i]->stream_res.tg);
|
||||
}
|
||||
|
||||
if (link->dc->hwss.setup_hpo_hw_control) {
|
||||
is_hpo_acquired = resource_is_hpo_acquired(state);
|
||||
if (was_hpo_acquired != is_hpo_acquired)
|
||||
link->dc->hwss.setup_hpo_hw_control(link->dc->hwseq, is_hpo_acquired);
|
||||
if (needs_divider_update && link->dc->res_pool->funcs->update_dc_state_for_encoder_switch) {
|
||||
link->dc->res_pool->funcs->update_dc_state_for_encoder_switch(link,
|
||||
link_setting, count,
|
||||
*pipes, &audio_output[0]);
|
||||
for (i = 0; i < count; i++) {
|
||||
pipes[i]->clock_source->funcs->program_pix_clk(
|
||||
pipes[i]->clock_source,
|
||||
&pipes[i]->stream_res.pix_clk_params,
|
||||
link->dc->link_srv->dp_get_encoding_format(&pipes[i]->link_config.dp_link_settings),
|
||||
&pipes[i]->pll_settings);
|
||||
|
||||
if (pipes[i]->stream_res.audio != NULL) {
|
||||
const struct link_hwss *link_hwss = get_link_hwss(
|
||||
link, &pipes[i]->link_res);
|
||||
|
||||
link_hwss->setup_audio_output(pipes[i], &audio_output[i],
|
||||
pipes[i]->stream_res.audio->inst);
|
||||
|
||||
pipes[i]->stream_res.audio->funcs->az_configure(
|
||||
pipes[i]->stream_res.audio,
|
||||
pipes[i]->stream->signal,
|
||||
&audio_output[i].crtc_info,
|
||||
&pipes[i]->stream->audio_info,
|
||||
&audio_output[i].dp_link_info);
|
||||
|
||||
if (link->dc->config.disable_hbr_audio_dp2 &&
|
||||
pipes[i]->stream_res.audio->funcs->az_disable_hbr_audio &&
|
||||
link->dc->link_srv->dp_is_128b_132b_signal(pipes[i]))
|
||||
pipes[i]->stream_res.audio->funcs->az_disable_hbr_audio(pipes[i]->stream_res.audio);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = count-1; i >= 0; i--)
|
||||
link_set_dpms_on(state, pipes[i]);
|
||||
// Toggle on HPO I/O if necessary
|
||||
is_hpo_acquired = resource_is_hpo_acquired(state);
|
||||
if (was_hpo_acquired != is_hpo_acquired && link->dc->hwss.setup_hpo_hw_control)
|
||||
link->dc->hwss.setup_hpo_hw_control(link->dc->hwseq, is_hpo_acquired);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
pipes[i]->stream_res.tg->funcs->enable_crtc(pipes[i]->stream_res.tg);
|
||||
|
||||
// Set DPMS on with stream update
|
||||
for (i = 0; i < state->stream_count; i++)
|
||||
if (state->streams[i] && state->streams[i]->link && state->streams[i]->link == link) {
|
||||
stream_update.stream = state->streams[i];
|
||||
stream_update.dpms_off = &dpms_off;
|
||||
dc_update_planes_and_stream(state->clk_mgr->ctx->dc, NULL, 0, state->streams[i], &stream_update);
|
||||
}
|
||||
}
|
||||
|
||||
static void dp_test_send_link_training(struct dc_link *link)
|
||||
|
|
|
|||
|
|
@ -1850,7 +1850,9 @@ static struct resource_funcs dcn31_res_pool_funcs = {
|
|||
.patch_unknown_plane_state = dcn20_patch_unknown_plane_state,
|
||||
.get_panel_config_defaults = dcn31_get_panel_config_defaults,
|
||||
.get_det_buffer_size = dcn31_get_det_buffer_size,
|
||||
.get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe
|
||||
.get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe,
|
||||
.update_dc_state_for_encoder_switch = dcn31_update_dc_state_for_encoder_switch,
|
||||
.build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params
|
||||
};
|
||||
|
||||
static struct clock_source *dcn30_clock_source_create(
|
||||
|
|
@ -2231,3 +2233,35 @@ struct resource_pool *dcn31_create_resource_pool(
|
|||
kfree(pool);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
enum dc_status dcn31_update_dc_state_for_encoder_switch(struct dc_link *link,
|
||||
struct dc_link_settings *link_setting,
|
||||
uint8_t pipe_count,
|
||||
struct pipe_ctx *pipes,
|
||||
struct audio_output *audio_output)
|
||||
{
|
||||
struct dc_state *state = link->dc->current_state;
|
||||
int i;
|
||||
|
||||
#if defined(CONFIG_DRM_AMD_DC_FP)
|
||||
for (i = 0; i < state->stream_count; i++)
|
||||
if (state->streams[i] && state->streams[i]->link && state->streams[i]->link == link)
|
||||
link->dc->hwss.calculate_pix_rate_divider((struct dc *)link->dc, state, state->streams[i]);
|
||||
|
||||
for (i = 0; i < pipe_count; i++) {
|
||||
link->dc->res_pool->funcs->build_pipe_pix_clk_params(&pipes[i]);
|
||||
|
||||
// Setup audio
|
||||
if (pipes[i].stream_res.audio != NULL)
|
||||
build_audio_output(state, &pipes[i], &audio_output[i]);
|
||||
}
|
||||
#else
|
||||
/* This DCN requires rate divider updates and audio reprogramming to allow DP1<-->DP2 link rate switching,
|
||||
* but the above will not compile on architectures without an FPU.
|
||||
*/
|
||||
DC_LOG_WARNING("%s: DP1<-->DP2 link retraining will not work on this DCN on non-FPU platforms", __func__);
|
||||
ASSERT(0);
|
||||
#endif
|
||||
|
||||
return DC_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,12 @@ struct resource_pool *dcn31_create_resource_pool(
|
|||
unsigned int dcn31_get_det_buffer_size(
|
||||
const struct dc_state *context);
|
||||
|
||||
enum dc_status dcn31_update_dc_state_for_encoder_switch(struct dc_link *link,
|
||||
struct dc_link_settings *link_setting,
|
||||
uint8_t pipe_count,
|
||||
struct pipe_ctx *pipes,
|
||||
struct audio_output *audio_output);
|
||||
|
||||
/*temp: B0 specific before switch to dcn313 headers*/
|
||||
#ifndef regPHYPLLF_PIXCLK_RESYNC_CNTL
|
||||
#define regPHYPLLF_PIXCLK_RESYNC_CNTL 0x007e
|
||||
|
|
|
|||
|
|
@ -1779,7 +1779,9 @@ static struct resource_funcs dcn314_res_pool_funcs = {
|
|||
.get_panel_config_defaults = dcn314_get_panel_config_defaults,
|
||||
.get_preferred_eng_id_dpia = dcn314_get_preferred_eng_id_dpia,
|
||||
.get_det_buffer_size = dcn31_get_det_buffer_size,
|
||||
.get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe
|
||||
.get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe,
|
||||
.update_dc_state_for_encoder_switch = dcn31_update_dc_state_for_encoder_switch,
|
||||
.build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params
|
||||
};
|
||||
|
||||
static struct clock_source *dcn30_clock_source_create(
|
||||
|
|
|
|||
|
|
@ -1844,7 +1844,9 @@ static struct resource_funcs dcn315_res_pool_funcs = {
|
|||
.get_panel_config_defaults = dcn315_get_panel_config_defaults,
|
||||
.get_power_profile = dcn315_get_power_profile,
|
||||
.get_det_buffer_size = dcn31_get_det_buffer_size,
|
||||
.get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe
|
||||
.get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe,
|
||||
.update_dc_state_for_encoder_switch = dcn31_update_dc_state_for_encoder_switch,
|
||||
.build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params
|
||||
};
|
||||
|
||||
static bool dcn315_resource_construct(
|
||||
|
|
|
|||
|
|
@ -1720,7 +1720,9 @@ static struct resource_funcs dcn316_res_pool_funcs = {
|
|||
.patch_unknown_plane_state = dcn20_patch_unknown_plane_state,
|
||||
.get_panel_config_defaults = dcn316_get_panel_config_defaults,
|
||||
.get_det_buffer_size = dcn31_get_det_buffer_size,
|
||||
.get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe
|
||||
.get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe,
|
||||
.update_dc_state_for_encoder_switch = dcn31_update_dc_state_for_encoder_switch,
|
||||
.build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params
|
||||
};
|
||||
|
||||
static bool dcn316_resource_construct(
|
||||
|
|
|
|||
|
|
@ -1786,7 +1786,9 @@ static struct resource_funcs dcn35_res_pool_funcs = {
|
|||
.get_panel_config_defaults = dcn35_get_panel_config_defaults,
|
||||
.get_preferred_eng_id_dpia = dcn35_get_preferred_eng_id_dpia,
|
||||
.get_det_buffer_size = dcn31_get_det_buffer_size,
|
||||
.get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe
|
||||
.get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe,
|
||||
.update_dc_state_for_encoder_switch = dcn31_update_dc_state_for_encoder_switch,
|
||||
.build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params
|
||||
};
|
||||
|
||||
static bool dcn35_resource_construct(
|
||||
|
|
|
|||
|
|
@ -1758,7 +1758,9 @@ static struct resource_funcs dcn351_res_pool_funcs = {
|
|||
.get_panel_config_defaults = dcn35_get_panel_config_defaults,
|
||||
.get_preferred_eng_id_dpia = dcn351_get_preferred_eng_id_dpia,
|
||||
.get_det_buffer_size = dcn31_get_det_buffer_size,
|
||||
.get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe
|
||||
.get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe,
|
||||
.update_dc_state_for_encoder_switch = dcn31_update_dc_state_for_encoder_switch,
|
||||
.build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params
|
||||
};
|
||||
|
||||
static bool dcn351_resource_construct(
|
||||
|
|
|
|||
|
|
@ -1759,7 +1759,9 @@ static struct resource_funcs dcn36_res_pool_funcs = {
|
|||
.patch_unknown_plane_state = dcn20_patch_unknown_plane_state,
|
||||
.get_panel_config_defaults = dcn35_get_panel_config_defaults,
|
||||
.get_preferred_eng_id_dpia = dcn36_get_preferred_eng_id_dpia,
|
||||
.get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe
|
||||
.get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe,
|
||||
.update_dc_state_for_encoder_switch = dcn31_update_dc_state_for_encoder_switch,
|
||||
.build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params
|
||||
};
|
||||
|
||||
static bool dcn36_resource_construct(
|
||||
|
|
|
|||
Loading…
Reference in New Issue