diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/core')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc.c | 37 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc_link.c | 87 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 63 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 33 |
5 files changed, 134 insertions, 90 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 8f0a13807d05..4713f09bcbf1 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -55,6 +55,7 @@ #include "link_encoder.h" #include "link_enc_cfg.h" +#include "dc_link.h" #include "dc_link_ddc.h" #include "dm_helpers.h" #include "mem_input.h" @@ -1322,11 +1323,10 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc, struct dc_link *link = sink->link; unsigned int i, enc_inst, tg_inst = 0; - // Seamless port only support single DP and EDP so far - if ((sink->sink_signal != SIGNAL_TYPE_DISPLAY_PORT && - sink->sink_signal != SIGNAL_TYPE_EDP) || - sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT_MST) + /* Support seamless boot on EDP displays only */ + if (sink->sink_signal != SIGNAL_TYPE_EDP) { return false; + } /* Check for enabled DIG to identify enabled display */ if (!link->link_enc->funcs->is_dig_enabled(link->link_enc)) @@ -1399,6 +1399,10 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc, if (crtc_timing->v_sync_width != hw_crtc_timing.v_sync_width) return false; + /* block DSC for now, as VBIOS does not currently support DSC timings */ + if (crtc_timing->flags.DSC) + return false; + if (dc_is_dp_signal(link->connector_signal)) { unsigned int pix_clk_100hz; @@ -1429,6 +1433,11 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc, return false; } + if (is_edp_ilr_optimization_required(link, crtc_timing)) { + DC_LOG_EVENT_LINK_TRAINING("Seamless boot disabled to optimize eDP link rate\n"); + return false; + } + return true; } @@ -2678,6 +2687,10 @@ static void commit_planes_for_stream(struct dc *dc, plane_state->triplebuffer_flips = true; } } + if (update_type == UPDATE_TYPE_FULL) { + /* force vsync flip when reconfiguring pipes to prevent underflow */ + plane_state->flip_immediate = false; + } } } @@ -2821,7 +2834,8 @@ static void commit_planes_for_stream(struct dc *dc, if (pipe_ctx->bottom_pipe || pipe_ctx->next_odm_pipe || !pipe_ctx->stream || pipe_ctx->stream != stream || - !pipe_ctx->plane_state->update_flags.bits.addr_update) + !pipe_ctx->plane_state->update_flags.bits.addr_update || + pipe_ctx->plane_state->skip_manual_trigger) continue; if (pipe_ctx->stream_res.tg->funcs->program_manual_trigger) @@ -3205,6 +3219,19 @@ void dc_link_remove_remote_sink(struct dc_link *link, struct dc_sink *sink) } } +void dc_wait_for_vblank(struct dc *dc, struct dc_stream_state *stream) +{ + int i; + + for (i = 0; i < dc->res_pool->pipe_count; i++) + if (dc->current_state->res_ctx.pipe_ctx[i].stream == stream) { + struct timing_generator *tg = + dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg; + tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK); + break; + } +} + void get_clock_requirements_for_state(struct dc_state *state, struct AsicStateEx *info) { info->displayClock = (unsigned int)state->bw_ctx.bw.dcn.clk.dispclk_khz; 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 29bc2874f6a7..f4374d83662a 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1679,21 +1679,27 @@ void link_destroy(struct dc_link **link) static void enable_stream_features(struct pipe_ctx *pipe_ctx) { struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->link; - union down_spread_ctrl old_downspread; - union down_spread_ctrl new_downspread; - core_link_read_dpcd(link, DP_DOWNSPREAD_CTRL, - &old_downspread.raw, sizeof(old_downspread)); + if (pipe_ctx->stream->signal != SIGNAL_TYPE_DISPLAY_PORT_MST) { + struct dc_link *link = stream->link; + union down_spread_ctrl old_downspread; + union down_spread_ctrl new_downspread; + + core_link_read_dpcd(link, DP_DOWNSPREAD_CTRL, + &old_downspread.raw, sizeof(old_downspread)); - new_downspread.raw = old_downspread.raw; + new_downspread.raw = old_downspread.raw; - new_downspread.bits.IGNORE_MSA_TIMING_PARAM = - (stream->ignore_msa_timing_param) ? 1 : 0; + new_downspread.bits.IGNORE_MSA_TIMING_PARAM = + (stream->ignore_msa_timing_param) ? 1 : 0; + + if (new_downspread.raw != old_downspread.raw) { + core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, + &new_downspread.raw, sizeof(new_downspread)); + } - if (new_downspread.raw != old_downspread.raw) { - core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, - &new_downspread.raw, sizeof(new_downspread)); + } else { + dm_helpers_mst_enable_stream_features(stream); } } @@ -2813,12 +2819,9 @@ bool dc_link_setup_psr(struct dc_link *link, psr_context->psr_level.u32all = 0; -#if defined(CONFIG_DRM_AMD_DC_DCN) /*skip power down the single pipe since it blocks the cstate*/ - if ((link->ctx->asic_id.chip_family == FAMILY_RV) && - ASICREV_IS_RAVEN(link->ctx->asic_id.hw_internal_rev)) + if (link->ctx->asic_id.chip_family >= FAMILY_RV) psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true; -#endif /* SMU will perform additional powerdown sequence. * For unsupported ASICs, set psr_level flag to skip PSR @@ -3139,50 +3142,6 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) return DC_OK; } -enum dc_status dc_link_reallocate_mst_payload(struct dc_link *link) -{ - int i; - struct pipe_ctx *pipe_ctx; - - // Clear all of MST payload then reallocate - for (i = 0; i < MAX_PIPES; i++) { - pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i]; - - /* driver enable split pipe for external monitors - * we have to check pipe_ctx is split pipe or not - * If it's split pipe, driver using top pipe to - * reaallocate. - */ - if (!pipe_ctx || pipe_ctx->top_pipe) - continue; - - if (pipe_ctx->stream && pipe_ctx->stream->link == link && - pipe_ctx->stream->dpms_off == false && - pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { - deallocate_mst_payload(pipe_ctx); - } - } - - for (i = 0; i < MAX_PIPES; i++) { - pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i]; - - if (!pipe_ctx || pipe_ctx->top_pipe) - continue; - - if (pipe_ctx->stream && pipe_ctx->stream->link == link && - pipe_ctx->stream->dpms_off == false && - pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { - /* enable/disable PHY will clear connection between BE and FE - * need to restore it. - */ - link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc, - pipe_ctx->stream_res.stream_enc->id, true); - dc_link_allocate_mst_payload(pipe_ctx); - } - } - - return DC_OK; -} #if defined(CONFIG_DRM_AMD_DC_HDCP) static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off) @@ -3296,7 +3255,8 @@ void core_link_enable_stream( /* eDP lit up by bios already, no need to enable again. */ if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP && - apply_edp_fast_boot_optimization) { + apply_edp_fast_boot_optimization && + !pipe_ctx->stream->timing.flags.DSC) { pipe_ctx->stream->dpms_off = false; #if defined(CONFIG_DRM_AMD_DC_HDCP) update_psp_stream_config(pipe_ctx, false); @@ -3358,8 +3318,10 @@ void core_link_enable_stream( /* Set DPS PPS SDP (AKA "info frames") */ if (pipe_ctx->stream->timing.flags.DSC) { if (dc_is_dp_signal(pipe_ctx->stream->signal) || - dc_is_virtual_signal(pipe_ctx->stream->signal)) + dc_is_virtual_signal(pipe_ctx->stream->signal)) { + dp_set_dsc_on_rx(pipe_ctx, true); dp_set_dsc_pps_sdp(pipe_ctx, true); + } } if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) @@ -3754,7 +3716,8 @@ bool dc_link_should_enable_fec(const struct dc_link *link) if ((link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT_MST && link->local_sink && link->local_sink->edid_caps.panel_patch.disable_fec) || - link->connector_signal == SIGNAL_TYPE_EDP) // Disable FEC for eDP + (link->connector_signal == SIGNAL_TYPE_EDP && + link->dc->debug.force_enable_edp_fec == false)) // Disable FEC for eDP is_fec_disable = true; if (dc_link_is_fec_supported(link) && !link->dc->debug.disable_fec && !is_fec_disable) 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 7d2e433c2275..3ff3d9e90983 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 @@ -1132,11 +1132,6 @@ static inline enum link_training_result perform_link_training_int( enum link_training_result status) { union lane_count_set lane_count_set = { {0} }; - union dpcd_training_pattern dpcd_pattern = { {0} }; - - /* 3. set training not in progress*/ - dpcd_pattern.v1_4.TRAINING_PATTERN_SET = DPCD_TRAINING_PATTERN_VIDEOIDLE; - dpcd_set_training_pattern(link, dpcd_pattern); /* 4. mainlink output idle pattern*/ dp_set_hw_test_pattern(link, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); @@ -1560,6 +1555,7 @@ enum link_training_result dc_link_dp_perform_link_training( { enum link_training_result status = LINK_TRAINING_SUCCESS; struct link_training_settings lt_settings; + union dpcd_training_pattern dpcd_pattern = { { 0 } }; bool fec_enable; uint8_t repeater_cnt; @@ -1624,6 +1620,9 @@ enum link_training_result dc_link_dp_perform_link_training( } } + /* 3. set training not in progress*/ + dpcd_pattern.v1_4.TRAINING_PATTERN_SET = DPCD_TRAINING_PATTERN_VIDEOIDLE; + dpcd_set_training_pattern(link, dpcd_pattern); if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) { status = perform_link_training_int(link, <_settings, @@ -2490,7 +2489,7 @@ static bool decide_dp_link_settings(struct dc_link *link, struct dc_link_setting return false; } -static bool decide_edp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw) +bool decide_edp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw) { struct dc_link_settings initial_link_setting; struct dc_link_settings current_link_setting; @@ -3582,6 +3581,8 @@ static bool retrieve_link_cap(struct dc_link *link) link->dpcd_caps.lttpr_caps.revision.raw >= 0x14); if (is_lttpr_present) CONN_DATA_DETECT(link, lttpr_dpcd_data, sizeof(lttpr_dpcd_data), "LTTPR Caps: "); + else + link->lttpr_mode = LTTPR_MODE_NON_LTTPR; } if (!is_lttpr_present) @@ -3892,7 +3893,7 @@ void detect_edp_sink_caps(struct dc_link *link) memset(supported_link_rates, 0, sizeof(supported_link_rates)); if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 && - (link->dc->config.optimize_edp_link_rate || + (link->dc->debug.optimize_edp_link_rate || link->reported_link_cap.link_rate == LINK_RATE_UNKNOWN)) { // Read DPCD 00010h - 0001Fh 16 bytes at one shot core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES, @@ -4718,3 +4719,51 @@ bool dc_link_set_default_brightness_aux(struct dc_link *link) } return false; } + +bool is_edp_ilr_optimization_required(struct dc_link *link, struct dc_crtc_timing *crtc_timing) +{ + struct dc_link_settings link_setting; + uint8_t link_bw_set; + uint8_t link_rate_set; + uint32_t req_bw; + union lane_count_set lane_count_set = { {0} }; + + ASSERT(link || crtc_timing); // invalid input + + if (link->dpcd_caps.edp_supported_link_rates_count == 0 || + !link->dc->debug.optimize_edp_link_rate) + return false; + + + // Read DPCD 00100h to find if standard link rates are set + core_link_read_dpcd(link, DP_LINK_BW_SET, + &link_bw_set, sizeof(link_bw_set)); + + if (link_bw_set) { + DC_LOG_EVENT_LINK_TRAINING("eDP ILR: Optimization required, VBIOS used link_bw_set\n"); + return true; + } + + // Read DPCD 00115h to find the edp link rate set used + core_link_read_dpcd(link, DP_LINK_RATE_SET, + &link_rate_set, sizeof(link_rate_set)); + + // Read DPCD 00101h to find out the number of lanes currently set + core_link_read_dpcd(link, DP_LANE_COUNT_SET, + &lane_count_set.raw, sizeof(lane_count_set)); + + req_bw = dc_bandwidth_in_kbps_from_timing(crtc_timing); + + decide_edp_link_settings(link, &link_setting, req_bw); + + if (link->dpcd_caps.edp_supported_link_rates[link_rate_set] != link_setting.link_rate || + lane_count_set.bits.LANE_COUNT_SET != link_setting.lane_count) { + DC_LOG_EVENT_LINK_TRAINING("eDP ILR: Optimization required, VBIOS link_rate_set not optimal\n"); + return true; + } + + DC_LOG_EVENT_LINK_TRAINING("eDP ILR: No optimization required, VBIOS set optimal link_rate_set\n"); + return false; +} + + diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c index 48ad1a8d4a74..b426f878fb99 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c @@ -431,7 +431,7 @@ static void dsc_optc_config_log(struct display_stream_compressor *dsc, DC_LOG_DSC("\tslice_width %d", config->slice_width); } -static bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable) +bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable) { struct dc *dc = pipe_ctx->stream->ctx->dc; struct dc_stream_state *stream = pipe_ctx->stream; @@ -541,7 +541,7 @@ bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable) goto out; if (enable) { - if (dp_set_dsc_on_rx(pipe_ctx, true)) { + { dp_set_dsc_on_stream(pipe_ctx, true); result = true; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index ac7a75887f95..8cb937c046aa 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -2506,26 +2506,31 @@ static void set_avi_info_frame( hdmi_info.bits.ITC = itc_value; } + if (stream->qs_bit == 1) { + if (color_space == COLOR_SPACE_SRGB || + color_space == COLOR_SPACE_2020_RGB_FULLRANGE) + hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_FULL_RANGE; + else if (color_space == COLOR_SPACE_SRGB_LIMITED || + color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE) + hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_LIMITED_RANGE; + else + hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_DEFAULT_RANGE; + } else + hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_DEFAULT_RANGE; + /* TODO : We should handle YCC quantization */ /* but we do not have matrix calculation */ - if (stream->qs_bit == 1 && - stream->qy_bit == 1) { + if (stream->qy_bit == 1) { if (color_space == COLOR_SPACE_SRGB || - color_space == COLOR_SPACE_2020_RGB_FULLRANGE) { - hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_FULL_RANGE; + color_space == COLOR_SPACE_2020_RGB_FULLRANGE) hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE; - } else if (color_space == COLOR_SPACE_SRGB_LIMITED || - color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE) { - hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_LIMITED_RANGE; + else if (color_space == COLOR_SPACE_SRGB_LIMITED || + color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE) hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE; - } else { - hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_DEFAULT_RANGE; + else hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE; - } - } else { - hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_DEFAULT_RANGE; - hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE; - } + } else + hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE; ///VIC format = stream->timing.timing_3d_format; |