diff options
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.c | 176 |
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); } |