summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/display/dc/core/dc_link.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/core/dc_link.c')
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link.c176
1 files changed, 137 insertions, 39 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 a789ea8af27f..9e51338441d0 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
@@ -235,7 +235,8 @@ bool dc_link_detect_sink(struct dc_link *link, enum dc_connection_type *type)
if (link->connector_signal == SIGNAL_TYPE_EDP) {
/*in case it is not on*/
- link->dc->hwss.edp_power_control(link, true);
+ if (!link->dc->config.edp_no_power_sequencing)
+ link->dc->hwss.edp_power_control(link, true);
link->dc->hwss.edp_wait_for_hpd_ready(link, true);
}
@@ -844,7 +845,7 @@ static bool discover_dp_mst_topology(struct dc_link *link, enum dc_detect_reason
return link->type == dc_connection_mst_branch;
}
-static bool reset_cur_dp_mst_topology(struct dc_link *link)
+bool reset_cur_dp_mst_topology(struct dc_link *link)
{
bool result = false;
DC_LOGGER_INIT(link->ctx->logger);
@@ -1016,11 +1017,11 @@ static bool detect_link_and_local_sink(struct dc_link *link,
bool same_edid = false;
enum dc_edid_status edid_status;
struct dc_context *dc_ctx = link->ctx;
+ struct dc *dc = dc_ctx->dc;
struct dc_sink *sink = NULL;
struct dc_sink *prev_sink = NULL;
struct dpcd_caps prev_dpcd_caps;
enum dc_connection_type new_connection_type = dc_connection_none;
- enum dc_connection_type pre_connection_type = dc_connection_none;
const uint32_t post_oui_delay = 30; // 30ms
DC_LOGGER_INIT(link->ctx->logger);
@@ -1057,7 +1058,6 @@ static bool detect_link_and_local_sink(struct dc_link *link,
link_disconnect_sink(link);
if (new_connection_type != dc_connection_none) {
- pre_connection_type = link->type;
link->type = new_connection_type;
link->link_state_valid = false;
@@ -1095,6 +1095,20 @@ static bool detect_link_and_local_sink(struct dc_link *link,
detect_edp_sink_caps(link);
read_current_link_settings_on_detect(link);
+
+ /* Disable power sequence on MIPI panel + converter
+ */
+ if (dc->config.enable_mipi_converter_optimization &&
+ dc_ctx->dce_version == DCN_VERSION_3_01 &&
+ link->dpcd_caps.sink_dev_id == DP_BRANCH_DEVICE_ID_0022B9 &&
+ memcmp(&link->dpcd_caps.branch_dev_name, DP_SINK_BRANCH_DEV_NAME_7580,
+ sizeof(link->dpcd_caps.branch_dev_name)) == 0) {
+ dc->config.edp_no_power_sequencing = true;
+
+ if (!link->dpcd_caps.set_power_state_capable_edp)
+ link->wa_flags.dp_keep_receiver_powered = true;
+ }
+
sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C_OVER_AUX;
sink_caps.signal = SIGNAL_TYPE_EDP;
break;
@@ -1130,11 +1144,6 @@ static bool detect_link_and_local_sink(struct dc_link *link,
(link->dpcd_caps.dongle_type !=
DISPLAY_DONGLE_DP_HDMI_CONVERTER))
converter_disable_audio = true;
-
- // link switch from MST to non-MST stop topology manager
- if (pre_connection_type == dc_connection_mst_branch &&
- link->type != dc_connection_mst_branch)
- dm_helpers_dp_mst_stop_top_mgr(link->ctx, link);
break;
}
@@ -1367,7 +1376,9 @@ bool dc_link_get_hpd_state(struct dc_link *dc_link)
static enum hpd_source_id get_hpd_line(struct dc_link *link)
{
struct gpio *hpd;
- enum hpd_source_id hpd_id = HPD_SOURCEID_UNKNOWN;
+ enum hpd_source_id hpd_id;
+
+ hpd_id = HPD_SOURCEID_UNKNOWN;
hpd = get_hpd_gpio(link->ctx->dc_bios, link->link_id,
link->ctx->gpio_service);
@@ -1406,7 +1417,9 @@ static enum hpd_source_id get_hpd_line(struct dc_link *link)
static enum channel_id get_ddc_line(struct dc_link *link)
{
struct ddc *ddc;
- enum channel_id channel = CHANNEL_ID_UNKNOWN;
+ enum channel_id channel;
+
+ channel = CHANNEL_ID_UNKNOWN;
ddc = dal_ddc_service_get_ddc_pin(link->ddc);
@@ -1513,7 +1526,7 @@ static bool dc_link_construct_legacy(struct dc_link *link,
const struct link_init_data *init_params)
{
uint8_t i;
- struct ddc_service_init_data ddc_service_init_data = { { 0 } };
+ struct ddc_service_init_data ddc_service_init_data = { 0 };
struct dc_context *dc_ctx = init_params->ctx;
struct encoder_init_data enc_init_data = { 0 };
struct panel_cntl_init_data panel_cntl_init_data = { 0 };
@@ -1690,7 +1703,7 @@ static bool dc_link_construct_legacy(struct dc_link *link,
enc_init_data.transmitter =
translate_encoder_to_transmitter(enc_init_data.encoder);
link->link_enc =
- link->dc->res_pool->funcs->link_enc_create(&enc_init_data);
+ link->dc->res_pool->funcs->link_enc_create(dc_ctx, &enc_init_data);
if (!link->link_enc) {
DC_ERROR("Failed to create link encoder!\n");
@@ -1783,6 +1796,7 @@ static bool dc_link_construct_legacy(struct dc_link *link,
*/
program_hpd_filter(link);
+ link->psr_settings.psr_vtotal_control_support = false;
link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
DC_LOG_DC("BIOS object table - %s finished successfully.\n", __func__);
@@ -1812,7 +1826,7 @@ create_fail:
static bool dc_link_construct_dpia(struct dc_link *link,
const struct link_init_data *init_params)
{
- struct ddc_service_init_data ddc_service_init_data = { { 0 } };
+ struct ddc_service_init_data ddc_service_init_data = { 0 };
struct dc_context *dc_ctx = init_params->ctx;
DC_LOGGER_INIT(dc_ctx->logger);
@@ -1955,7 +1969,8 @@ static enum dc_status enable_link_dp(struct dc_state *state,
enum dc_status status;
bool skip_video_pattern;
struct dc_link *link = stream->link;
- struct dc_link_settings link_settings = {0};
+ const struct dc_link_settings *link_settings =
+ &pipe_ctx->link_config.dp_link_settings;
bool fec_enable;
int i;
bool apply_seamless_boot_optimization = false;
@@ -1972,9 +1987,6 @@ static enum dc_status enable_link_dp(struct dc_state *state,
}
}
- /* get link settings for video mode timing */
- decide_link_settings(stream, &link_settings);
-
/* Train with fallback when enabling DPIA link. Conventional links are
* trained with fallback during sink detection.
*/
@@ -1985,7 +1997,7 @@ static enum dc_status enable_link_dp(struct dc_state *state,
* Temporary w/a to get DP2.0 link rates to work with SST.
* TODO DP2.0 - Workaround: Remove w/a if and when the issue is resolved.
*/
- if (dp_get_link_encoding_format(&link_settings) == DP_128b_132b_ENCODING &&
+ if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING &&
pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
link->dc->debug.set_mst_en_for_sst) {
dp_enable_mst_on_sink(link, true);
@@ -1993,15 +2005,16 @@ static enum dc_status enable_link_dp(struct dc_state *state,
if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP) {
/*in case it is not on*/
- link->dc->hwss.edp_power_control(link, true);
+ if (!link->dc->config.edp_no_power_sequencing)
+ link->dc->hwss.edp_power_control(link, true);
link->dc->hwss.edp_wait_for_hpd_ready(link, true);
}
- if (dp_get_link_encoding_format(&link_settings) == DP_128b_132b_ENCODING) {
+ if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
/* TODO - DP2.0 HW: calculate 32 symbol clock for HPO encoder */
} else {
pipe_ctx->stream_res.pix_clk_params.requested_sym_clk =
- link_settings.link_rate * LINK_RATE_REF_FREQ_IN_KHZ;
+ link_settings->link_rate * LINK_RATE_REF_FREQ_IN_KHZ;
if (state->clk_mgr && !apply_seamless_boot_optimization)
state->clk_mgr->funcs->update_clocks(state->clk_mgr,
state, false);
@@ -2017,16 +2030,15 @@ static enum dc_status enable_link_dp(struct dc_state *state,
skip_video_pattern = true;
- if (link_settings.link_rate == LINK_RATE_LOW)
+ if (link_settings->link_rate == LINK_RATE_LOW)
skip_video_pattern = false;
- if (perform_link_training_with_retries(&link_settings,
+ if (perform_link_training_with_retries(link_settings,
skip_video_pattern,
LINK_TRAINING_ATTEMPTS,
pipe_ctx,
pipe_ctx->stream->signal,
do_fallback)) {
- link->cur_link_settings = link_settings;
status = DC_OK;
} else {
status = DC_FAIL_DP_LINK_TRAINING;
@@ -2037,7 +2049,7 @@ static enum dc_status enable_link_dp(struct dc_state *state,
else
fec_enable = true;
- if (dp_get_link_encoding_format(&link_settings) == DP_8b_10b_ENCODING)
+ if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING)
dp_set_fec_enable(link, fec_enable);
// during mode set we do DP_SET_POWER off then on, aux writes are lost
@@ -2113,6 +2125,26 @@ void dc_link_blank_all_dp_displays(struct dc *dc)
}
+void dc_link_blank_all_edp_displays(struct dc *dc)
+{
+ unsigned int i;
+ uint8_t dpcd_power_state = '\0';
+ enum dc_status status = DC_ERROR_UNEXPECTED;
+
+ for (i = 0; i < dc->link_count; i++) {
+ if ((dc->links[i]->connector_signal != SIGNAL_TYPE_EDP) ||
+ (!dc->links[i]->edp_sink_present))
+ continue;
+
+ /* if any of the displays are lit up turn them off */
+ status = core_link_read_dpcd(dc->links[i], DP_SET_POWER,
+ &dpcd_power_state, sizeof(dpcd_power_state));
+
+ if (status == DC_OK && dpcd_power_state == DP_POWER_STATE_D0)
+ dc_link_blank_dp_stream(dc->links[i], true);
+ }
+}
+
void dc_link_blank_dp_stream(struct dc_link *link, bool hw_init)
{
unsigned int j;
@@ -2699,6 +2731,22 @@ static void enable_link_lvds(struct pipe_ctx *pipe_ctx)
}
+bool dc_power_alpm_dpcd_enable(struct dc_link *link, bool enable)
+{
+ bool ret = false;
+ union dpcd_alpm_configuration alpm_config;
+
+ if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) {
+ memset(&alpm_config, 0, sizeof(alpm_config));
+
+ alpm_config.bits.ENABLE = (enable ? true : false);
+ ret = dm_helpers_dp_write_dpcd(link->ctx, link,
+ DP_RECEIVER_ALPM_CONFIG, &alpm_config.raw,
+ sizeof(alpm_config.raw));
+ }
+ return ret;
+}
+
/****************************enable_link***********************************/
static enum dc_status enable_link(
struct dc_state *state,
@@ -3193,6 +3241,7 @@ bool dc_link_setup_psr(struct dc_link *link,
unsigned int panel_inst;
/* updateSinkPsrDpcdConfig*/
union dpcd_psr_configuration psr_configuration;
+ union dpcd_sink_active_vtotal_control_mode vtotal_control = {0};
psr_context->controllerId = CONTROLLER_ID_UNDEFINED;
@@ -3218,7 +3267,7 @@ bool dc_link_setup_psr(struct dc_link *link,
psr_config->psr_frame_capture_indication_req;
/* Check for PSR v2*/
- if (psr_config->psr_version == 0x2) {
+ if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) {
/* For PSR v2 selective update.
* Indicates whether sink should start capturing
* immediately following active scan line,
@@ -3229,6 +3278,14 @@ bool dc_link_setup_psr(struct dc_link *link,
* IRQ_HPD when CRC mismatch is detected.
*/
psr_configuration.bits.IRQ_HPD_WITH_CRC_ERROR = 1;
+ /* For PSR v2, set the bit when the Source device will
+ * be enabling PSR2 operation.
+ */
+ psr_configuration.bits.ENABLE_PSR2 = 1;
+ /* For PSR v2, the Sink device must be able to receive
+ * SU region updates early in the frame time.
+ */
+ psr_configuration.bits.EARLY_TRANSPORT_ENABLE = 1;
}
dm_helpers_dp_write_dpcd(
@@ -3238,6 +3295,23 @@ bool dc_link_setup_psr(struct dc_link *link,
&psr_configuration.raw,
sizeof(psr_configuration.raw));
+ if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) {
+ dc_power_alpm_dpcd_enable(link, true);
+ psr_context->su_granularity_required =
+ psr_config->su_granularity_required;
+ psr_context->su_y_granularity =
+ psr_config->su_y_granularity;
+ psr_context->line_time_in_us =
+ psr_config->line_time_in_us;
+
+ if (link->psr_settings.psr_vtotal_control_support) {
+ psr_context->rate_control_caps = psr_config->rate_control_caps;
+ vtotal_control.bits.ENABLE = true;
+ core_link_write_dpcd(link, DP_SINK_PSR_ACTIVE_VTOTAL_CONTROL_MODE,
+ &vtotal_control.raw, sizeof(vtotal_control.raw));
+ }
+ }
+
psr_context->channel = link->ddc->ddc_pin->hw_info.ddc_channel;
psr_context->transmitterId = link->link_enc->transmitter;
psr_context->engineId = link->link_enc->preferred_engine;
@@ -3298,6 +3372,7 @@ bool dc_link_setup_psr(struct dc_link *link,
switch(link->ctx->asic_id.chip_family) {
case FAMILY_YELLOW_CARP:
case AMDGPU_FAMILY_GC_10_3_6:
+ case AMDGPU_FAMILY_GC_11_0_2:
if(!dc->debug.disable_z10)
psr_context->psr_level.bits.SKIP_CRTC_DISABLE = false;
break;
@@ -3324,6 +3399,10 @@ bool dc_link_setup_psr(struct dc_link *link,
*/
psr_context->psr_level.bits.DISABLE_PSR_ENTRY_ABORT = 1;
+ /* enable ALPM */
+ psr_context->psr_level.bits.DISABLE_ALPM = 0;
+ psr_context->psr_level.bits.ALPM_DEFAULT_PD_MODE = 1;
+
/* Controls additional delay after remote frame capture before
* continuing power down, default = 0
*/
@@ -3364,6 +3443,19 @@ void dc_link_get_psr_residency(const struct dc_link *link, uint32_t *residency)
*residency = 0;
}
+bool dc_link_set_sink_vtotal_in_psr_active(const struct dc_link *link, uint16_t psr_vtotal_idle, uint16_t psr_vtotal_su)
+{
+ struct dc *dc = link->ctx->dc;
+ struct dmub_psr *psr = dc->res_pool->psr;
+
+ if (psr == NULL || !link->psr_settings.psr_feature_enabled || !link->psr_settings.psr_vtotal_control_support)
+ return false;
+
+ psr->funcs->psr_set_sink_vtotal_in_psr_active(psr, psr_vtotal_idle, psr_vtotal_su);
+
+ return true;
+}
+
const struct dc_link_status *dc_link_get_status(const struct dc_link *link)
{
return &link->link_status;
@@ -3533,6 +3625,7 @@ static enum dc_status dc_link_update_sst_payload(struct pipe_ctx *pipe_ctx,
"allocation table for "
"pipe idx: %d\n",
pipe_ctx->pipe_idx);
+ return DC_FAIL_DP_PAYLOAD_ALLOCATION;
}
proposed_table.stream_allocations[0].hpo_dp_stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
@@ -3693,7 +3786,6 @@ enum dc_status dc_link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw
struct fixed31_32 pbn_per_slot;
struct dp_mst_stream_allocation_table proposed_table = {0};
uint8_t i;
- enum act_return_status ret;
const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
DC_LOGGER_INIT(link->ctx->logger);
@@ -3741,11 +3833,14 @@ enum dc_status dc_link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw
for (i = 0; i < MAX_CONTROLLER_NUM; i++) {
DC_LOG_MST("stream_enc[%d]: %p "
+ "stream[%d].hpo_dp_stream_enc: %p "
"stream[%d].vcp_id: %d "
"stream[%d].slot_count: %d\n",
i,
(void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc,
i,
+ (void *) link->mst_stream_alloc_table.stream_allocations[i].hpo_dp_stream_enc,
+ i,
link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
i,
link->mst_stream_alloc_table.stream_allocations[i].slot_count);
@@ -3764,7 +3859,7 @@ enum dc_status dc_link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw
&link->mst_stream_alloc_table);
/* poll for immediate branch device ACT handled */
- ret = dm_helpers_dp_mst_poll_for_allocation_change_trigger(
+ dm_helpers_dp_mst_poll_for_allocation_change_trigger(
stream->ctx,
stream);
@@ -3778,7 +3873,6 @@ enum dc_status dc_link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t
struct fixed31_32 avg_time_slots_per_mtp;
struct fixed31_32 pbn;
struct fixed31_32 pbn_per_slot;
- struct link_encoder *link_encoder = link->link_enc;
struct dp_mst_stream_allocation_table proposed_table = {0};
uint8_t i;
enum act_return_status ret;
@@ -3806,11 +3900,14 @@ enum dc_status dc_link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t
for (i = 0; i < MAX_CONTROLLER_NUM; i++) {
DC_LOG_MST("stream_enc[%d]: %p "
+ "stream[%d].hpo_dp_stream_enc: %p "
"stream[%d].vcp_id: %d "
"stream[%d].slot_count: %d\n",
i,
(void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc,
i,
+ (void *) link->mst_stream_alloc_table.stream_allocations[i].hpo_dp_stream_enc,
+ i,
link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
i,
link->mst_stream_alloc_table.stream_allocations[i].slot_count);
@@ -3819,8 +3916,13 @@ enum dc_status dc_link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t
ASSERT(proposed_table.stream_count > 0);
/* update mst stream allocation table hardware state */
- link_encoder->funcs->update_mst_stream_allocation_table(
- link_encoder,
+ if (link_hwss->ext.update_stream_allocation_table == NULL ||
+ dp_get_link_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) {
+ DC_LOG_ERROR("Failure: unknown encoding format\n");
+ return DC_ERROR_UNEXPECTED;
+ }
+
+ link_hwss->ext.update_stream_allocation_table(link, &pipe_ctx->link_res,
&link->mst_stream_alloc_table);
/* poll for immediate branch device ACT handled */
@@ -4020,11 +4122,10 @@ static void fpga_dp_hpo_enable_link_and_stream(struct dc_state *state, struct pi
struct fixed31_32 avg_time_slots_per_mtp;
uint8_t req_slot_count = 0;
uint8_t vc_id = 1; /// VC ID always 1 for SST
- struct dc_link_settings link_settings = {0};
+ struct dc_link_settings link_settings = pipe_ctx->link_config.dp_link_settings;
const struct link_hwss *link_hwss = get_link_hwss(stream->link, &pipe_ctx->link_res);
DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
- decide_link_settings(stream, &link_settings);
stream->link->cur_link_settings = link_settings;
if (link_hwss->ext.enable_dp_link_output)
@@ -4284,7 +4385,7 @@ void core_link_enable_stream(
dp_set_dsc_enable(pipe_ctx, true);
}
- if (pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) {
+ if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) {
core_link_set_avmute(pipe_ctx, false);
}
}
@@ -4498,10 +4599,7 @@ void dc_link_set_preferred_link_settings(struct dc *dc,
if (link_stream->dpms_off)
return;
- decide_link_settings(link_stream, &store_settings);
-
- if ((store_settings.lane_count != LANE_COUNT_UNKNOWN) &&
- (store_settings.link_rate != LINK_RATE_UNKNOWN))
+ if (decide_link_settings(link_stream, &store_settings))
dp_retrain_link_dp_test(link, &store_settings, false);
}