From: Tom Chung <chiahsuan.chung@xxxxxxx> [Why] Enable the Panel Replay if eDP panel and ASIC support. (prioritize Panel Replay over PSR) [How] - Setup the Panel Replay config during the device init (prioritize Panel Replay over PSR). - Separate the Replay init function into two functions amdgpu_dm_link_setup_replay() and amdgpu_dm_set_replay_caps() to fix the issue in the earlier commit that cause PSR and Replay enabled at the same time. Reviewed-by: Sun peng Li <sunpeng.li@xxxxxxx> Acked-by: Alex Hung <alex.hung@xxxxxxx> Signed-off-by: Tom Chung <chiahsuan.chung@xxxxxxx> --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 42 ++++++- .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 59 +++++++-- .../amd/display/amdgpu_dm/amdgpu_dm_replay.c | 119 ++++++++++-------- .../amd/display/amdgpu_dm/amdgpu_dm_replay.h | 4 +- 4 files changed, 156 insertions(+), 68 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 95ff3800fc87..f9e41006ac87 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -67,6 +67,7 @@ #include "amdgpu_dm_debugfs.h" #endif #include "amdgpu_dm_psr.h" +#include "amdgpu_dm_replay.h" #include "ivsrcid/ivsrcid_vislands30.h" @@ -4393,6 +4394,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) enum dc_connection_type new_connection_type = dc_connection_none; const struct dc_plane_cap *plane; bool psr_feature_enabled = false; + bool replay_feature_enabled = false; int max_overlay = dm->dc->caps.max_slave_planes; dm->display_indexes_num = dm->dc->caps.max_streams; @@ -4504,6 +4506,23 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) } } + /* Determine whether to enable Replay support by default. */ + if (!(amdgpu_dc_debug_mask & DC_DISABLE_REPLAY)) { + switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { + case IP_VERSION(3, 1, 4): + case IP_VERSION(3, 1, 5): + case IP_VERSION(3, 1, 6): + case IP_VERSION(3, 2, 0): + case IP_VERSION(3, 2, 1): + case IP_VERSION(3, 5, 0): + replay_feature_enabled = true; + break; + default: + replay_feature_enabled = amdgpu_dc_feature_mask & DC_REPLAY_MASK; + break; + } + } + /* loops over all connectors on the board */ for (i = 0; i < link_cnt; i++) { struct dc_link *link = NULL; @@ -4572,6 +4591,11 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) amdgpu_dm_update_connector_after_detect(aconnector); setup_backlight_device(dm, aconnector); + /* Disable PSR if Replay can be enabled */ + if (replay_feature_enabled) + if (amdgpu_dm_set_replay_caps(link, aconnector)) + psr_feature_enabled = false; + if (psr_feature_enabled) amdgpu_dm_set_psr_caps(link); @@ -8521,10 +8545,17 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, dm_update_pflip_irq_state(drm_to_adev(dev), acrtc_attach); - if ((acrtc_state->update_type > UPDATE_TYPE_FAST) && - acrtc_state->stream->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED && - !acrtc_state->stream->link->psr_settings.psr_feature_enabled) - amdgpu_dm_link_setup_psr(acrtc_state->stream); + if (acrtc_state->update_type > UPDATE_TYPE_FAST) { + if (acrtc_state->stream->link->replay_settings.config.replay_supported && + !acrtc_state->stream->link->replay_settings.replay_feature_enabled) { + struct amdgpu_dm_connector *aconn = + (struct amdgpu_dm_connector *)acrtc_state->stream->dm_stream_context; + amdgpu_dm_link_setup_replay(acrtc_state->stream->link, aconn); + } else if (acrtc_state->stream->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED && + !acrtc_state->stream->link->psr_settings.psr_feature_enabled) { + amdgpu_dm_link_setup_psr(acrtc_state->stream); + } + } /* Decrement skip count when PSR is enabled and we're doing fast updates. */ if (acrtc_state->update_type == UPDATE_TYPE_FAST && @@ -8813,11 +8844,12 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, } } /* for_each_crtc_in_state() */ - /* if there mode set or reset, disable eDP PSR */ + /* if there mode set or reset, disable eDP PSR, Replay */ if (mode_set_reset_required) { if (dm->vblank_control_workqueue) flush_workqueue(dm->vblank_control_workqueue); + amdgpu_dm_replay_disable_all(dm); amdgpu_dm_psr_disable_all(dm); } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c index 6e715ef3a556..f64c5ffed234 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c @@ -29,6 +29,7 @@ #include "dc.h" #include "amdgpu.h" #include "amdgpu_dm_psr.h" +#include "amdgpu_dm_replay.h" #include "amdgpu_dm_crtc.h" #include "amdgpu_dm_plane.h" #include "amdgpu_dm_trace.h" @@ -95,6 +96,48 @@ bool amdgpu_dm_crtc_vrr_active(struct dm_crtc_state *dm_state) dm_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED; } +/** + * The DRM vblank counter enable/disable action is used as the trigger to enable + * or disable various panel self-refresh features: + * + * Panel Replay and PSR SU + * - Enable when: + * - vblank counter is disabled + * - entry is allowed: usermode demonstrates an adequate number of fast + * commits) + * - CRC capture window isn't active + * - Keep enabled even when vblank counter gets enabled + * + * PSR1 + * - Enable condition same as above + * - Disable when vblank counter is enabled + */ +static void amdgpu_dm_crtc_set_panel_sr_feature( + struct vblank_control_work *vblank_work, + bool vblank_enabled, bool allow_sr_entry) +{ + struct dc_link *link = vblank_work->stream->link; + bool is_sr_active = (link->replay_settings.replay_allow_active || + link->psr_settings.psr_allow_active); + bool is_crc_window_active = false; + +#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY + is_crc_window_active = + amdgpu_dm_crc_window_is_activated(&vblank_work->acrtc->base); +#endif + + if (link->replay_settings.replay_feature_enabled && + allow_sr_entry && !is_sr_active && !is_crc_window_active) { + amdgpu_dm_replay_enable(vblank_work->stream, true); + } else if (vblank_enabled) { + if (link->psr_settings.psr_version < DC_PSR_VERSION_SU_1 && is_sr_active) + amdgpu_dm_psr_disable(vblank_work->stream); + } else if (link->psr_settings.psr_feature_enabled && + allow_sr_entry && !is_sr_active && !is_crc_window_active) { + amdgpu_dm_psr_enable(vblank_work->stream); + } +} + static void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work) { struct vblank_control_work *vblank_work = @@ -123,18 +166,10 @@ static void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work) * fill_dc_dirty_rects(). */ if (vblank_work->stream && vblank_work->stream->link) { - if (vblank_work->enable) { - if (vblank_work->stream->link->psr_settings.psr_version < DC_PSR_VERSION_SU_1 && - vblank_work->stream->link->psr_settings.psr_allow_active) - amdgpu_dm_psr_disable(vblank_work->stream); - } else if (vblank_work->stream->link->psr_settings.psr_feature_enabled && - !vblank_work->stream->link->psr_settings.psr_allow_active && -#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY - !amdgpu_dm_crc_window_is_activated(&vblank_work->acrtc->base) && -#endif - vblank_work->acrtc->dm_irq_params.allow_psr_entry) { - amdgpu_dm_psr_enable(vblank_work->stream); - } + amdgpu_dm_crtc_set_panel_sr_feature( + vblank_work, vblank_work->enable, + vblank_work->acrtc->dm_irq_params.allow_psr_entry || + vblank_work->stream->link->replay_settings.replay_feature_enabled); } mutex_unlock(&dm->dc_lock); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c index 5ce542b1f860..738a58eebba7 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c @@ -60,21 +60,26 @@ static bool link_supports_replay(struct dc_link *link, struct amdgpu_dm_connecto if (!as_caps->dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT) return false; + // Sink shall populate line deviation information + if (dpcd_caps->pr_info.pixel_deviation_per_line == 0 || + dpcd_caps->pr_info.max_deviation_line == 0) + return false; + return true; } /* - * amdgpu_dm_setup_replay() - setup replay configuration + * amdgpu_dm_set_replay_caps() - setup Replay capabilities * @link: link * @aconnector: aconnector * */ -bool amdgpu_dm_setup_replay(struct dc_link *link, struct amdgpu_dm_connector *aconnector) +bool amdgpu_dm_set_replay_caps(struct dc_link *link, struct amdgpu_dm_connector *aconnector) { - struct replay_config pr_config; + struct replay_config pr_config = { 0 }; union replay_debug_flags *debug_flags = NULL; - // For eDP, if Replay is supported, return true to skip checks + // If Replay is already set to support, return true to skip checks if (link->replay_settings.config.replay_supported) return true; @@ -87,27 +92,50 @@ bool amdgpu_dm_setup_replay(struct dc_link *link, struct amdgpu_dm_connector *ac if (!link_supports_replay(link, aconnector)) return false; - // Mark Replay is supported in link and update related attributes + // Mark Replay is supported in pr_config pr_config.replay_supported = true; - pr_config.replay_power_opt_supported = 0; - pr_config.replay_enable_option |= pr_enable_option_static_screen; - pr_config.replay_timing_sync_supported = aconnector->max_vfreq >= 2 * aconnector->min_vfreq; - - if (!pr_config.replay_timing_sync_supported) - pr_config.replay_enable_option &= ~pr_enable_option_general_ui; debug_flags = (union replay_debug_flags *)&pr_config.debug_flags; debug_flags->u32All = 0; debug_flags->bitfields.visual_confirm = link->ctx->dc->debug.visual_confirm == VISUAL_CONFIRM_REPLAY; - link->replay_settings.replay_feature_enabled = true; - init_replay_config(link, &pr_config); return true; } +/* + * amdgpu_dm_link_setup_replay() - configure replay link + * @link: link + * @aconnector: aconnector + * + */ +bool amdgpu_dm_link_setup_replay(struct dc_link *link, struct amdgpu_dm_connector *aconnector) +{ + struct replay_config *pr_config; + + if (link == NULL || aconnector == NULL) + return false; + + pr_config = &link->replay_settings.config; + + if (!pr_config->replay_supported) + return false; + + pr_config->replay_power_opt_supported = 0x11; + pr_config->replay_smu_opt_supported = false; + pr_config->replay_enable_option |= pr_enable_option_static_screen; + pr_config->replay_support_fast_resync_in_ultra_sleep_mode = aconnector->max_vfreq >= 2 * aconnector->min_vfreq; + pr_config->replay_timing_sync_supported = false; + + if (!pr_config->replay_timing_sync_supported) + pr_config->replay_enable_option &= ~pr_enable_option_general_ui; + + link->replay_settings.replay_feature_enabled = true; + + return true; +} /* * amdgpu_dm_replay_enable() - enable replay f/w @@ -117,51 +145,23 @@ bool amdgpu_dm_setup_replay(struct dc_link *link, struct amdgpu_dm_connector *ac */ bool amdgpu_dm_replay_enable(struct dc_stream_state *stream, bool wait) { - uint64_t state; - unsigned int retry_count; bool replay_active = true; - const unsigned int max_retry = 1000; - bool force_static = true; struct dc_link *link = NULL; - if (stream == NULL) return false; link = stream->link; - if (link == NULL) - return false; - - link->dc->link_srv->edp_setup_replay(link, stream); - - link->dc->link_srv->edp_set_replay_allow_active(link, NULL, false, false, NULL); - - link->dc->link_srv->edp_set_replay_allow_active(link, &replay_active, false, true, NULL); - - if (wait == true) { - - for (retry_count = 0; retry_count <= max_retry; retry_count++) { - dc_link_get_replay_state(link, &state); - if (replay_active) { - if (state != REPLAY_STATE_0 && - (!force_static || state == REPLAY_STATE_3)) - break; - } else { - if (state == REPLAY_STATE_0) - break; - } - udelay(500); - } - - /* assert if max retry hit */ - if (retry_count >= max_retry) - ASSERT(0); - } else { - /* To-do: Add trace log */ + if (link) { + link->dc->link_srv->edp_setup_replay(link, stream); + link->dc->link_srv->edp_set_coasting_vtotal(link, stream->timing.v_total); + DRM_DEBUG_DRIVER("Enabling replay...\n"); + link->dc->link_srv->edp_set_replay_allow_active(link, &replay_active, wait, false, NULL); + return true; } - return true; + return false; } /* @@ -172,12 +172,31 @@ bool amdgpu_dm_replay_enable(struct dc_stream_state *stream, bool wait) */ bool amdgpu_dm_replay_disable(struct dc_stream_state *stream) { + bool replay_active = false; + struct dc_link *link = NULL; - if (stream->link) { + if (stream == NULL) + return false; + + link = stream->link; + + if (link) { DRM_DEBUG_DRIVER("Disabling replay...\n"); - stream->link->dc->link_srv->edp_set_replay_allow_active(stream->link, NULL, false, false, NULL); + link->dc->link_srv->edp_set_replay_allow_active(stream->link, &replay_active, true, false, NULL); return true; } return false; } + +/* + * amdgpu_dm_replay_disable_all() - disable replay f/w + * if replay is enabled on any stream + * + * Return: true if success + */ +bool amdgpu_dm_replay_disable_all(struct amdgpu_display_manager *dm) +{ + DRM_DEBUG_DRIVER("Disabling replay if replay is enabled on any stream\n"); + return dc_set_replay_allow_active(dm->dc, false); +} diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.h index 01cba3cd6246..f0d30eb47312 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.h @@ -40,7 +40,9 @@ enum replay_enable_option { bool amdgpu_dm_replay_enable(struct dc_stream_state *stream, bool enable); -bool amdgpu_dm_setup_replay(struct dc_link *link, struct amdgpu_dm_connector *aconnector); +bool amdgpu_dm_set_replay_caps(struct dc_link *link, struct amdgpu_dm_connector *aconnector); +bool amdgpu_dm_link_setup_replay(struct dc_link *link, struct amdgpu_dm_connector *aconnector); bool amdgpu_dm_replay_disable(struct dc_stream_state *stream); +bool amdgpu_dm_replay_disable_all(struct amdgpu_display_manager *dm); #endif /* AMDGPU_DM_AMDGPU_DM_REPLAY_H_ */ -- 2.34.1