From: Lohita Mudimela <[email protected]> [Why] Extract all Replay related functions from power.c and power_helpers.c into a new power_replay.c module for better code organization and maintainability.
[How] Create new power_replay.c file containing Replay-related functions moved from power.c and power_helpers.c . Update mod_power.h with function declarations. Maintain forward declaration for type compatibility. Reviewed-by: Robin Chen <[email protected]> Signed-off-by: Lohita Mudimela <[email protected]> Signed-off-by: Ivan Lipski <[email protected]> --- .../drm/amd/display/modules/power/Makefile | 4 +- .../gpu/drm/amd/display/modules/power/power.c | 781 +-------------- .../drm/amd/display/modules/power/power_abm.c | 2 - .../amd/display/modules/power/power_helpers.c | 92 -- .../amd/display/modules/power/power_helpers.h | 5 + .../amd/display/modules/power/power_replay.c | 911 ++++++++++++++++++ 6 files changed, 921 insertions(+), 874 deletions(-) create mode 100644 drivers/gpu/drm/amd/display/modules/power/power_replay.c diff --git a/drivers/gpu/drm/amd/display/modules/power/Makefile b/drivers/gpu/drm/amd/display/modules/power/Makefile index fc4ba5873fad..3000f392bdbc 100644 --- a/drivers/gpu/drm/amd/display/modules/power/Makefile +++ b/drivers/gpu/drm/amd/display/modules/power/Makefile @@ -23,9 +23,9 @@ # Makefile for the 'power' sub-module of DAL. # -MOD_POWER = power_helpers.o power.o power_abm.o power_psr.o +MOD_POWER = power_helpers.o power.o power_abm.o power_psr.o power_replay.o AMD_DAL_MOD_POWER = $(addprefix $(AMDDALPATH)/modules/power/,$(MOD_POWER)) #$(info ************ DAL POWER MODULE MAKEFILE ************) -AMD_DISPLAY_FILES += $(AMD_DAL_MOD_POWER) +AMD_DISPLAY_FILES += $(AMD_DAL_MOD_POWER) \ No newline at end of file diff --git a/drivers/gpu/drm/amd/display/modules/power/power.c b/drivers/gpu/drm/amd/display/modules/power/power.c index 214ecc1f550d..1dd65bdf8cc9 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power.c +++ b/drivers/gpu/drm/amd/display/modules/power/power.c @@ -455,7 +455,6 @@ bool mod_power_replace_stream(struct mod_power *mod_power, return true; } - bool mod_power_notify_mode_change(struct mod_power *mod_power, const struct dc_stream_state *stream, bool is_hdr) @@ -465,7 +464,6 @@ bool mod_power_notify_mode_change(struct mod_power *mod_power, struct dc_link *link = NULL; struct dc *dc = NULL; unsigned int panel_inst = 0; - int active_replay_events = 0; if ((mod_power == NULL) || (stream == NULL)) return false; @@ -482,7 +480,7 @@ bool mod_power_notify_mode_change(struct mod_power *mod_power, dc = core_power->dc; link = dc_stream_get_link(stream); - active_replay_events = core_power->map[stream_index].replay_events; + if (link != NULL && dc_get_edp_link_panel_inst(dc, link, &panel_inst)) { ASSERT(link->ddc->ddc_pin->hw_info.ddc_channel <= 0xFF); uint8_t aux_inst = (uint8_t)link->ddc->ddc_pin->hw_info.ddc_channel; @@ -492,782 +490,9 @@ bool mod_power_notify_mode_change(struct mod_power *mod_power, /* Handle PSR notification */ mod_power_psr_notify_mode_change(mod_power, stream, link, stream_index); - link->replay_settings.replay_smu_opt_enable = - (link->replay_settings.config.replay_smu_opt_supported && - mod_power_only_edp(dc->current_state, stream)); - - if (active_replay_events & replay_event_os_request_force_ffu) { - link->replay_settings.config.os_request_force_ffu = true; - } - - if (dc_is_embedded_signal(stream->signal)) - dc->link_srv->dp_setup_replay(link, stream); - } - - return true; -} - -static bool mod_power_set_replay_active(struct dc_stream_state *stream, - bool replay_active, - bool wait, - bool force_static) -{ - uint64_t state; - unsigned int retry_count; - const unsigned int max_retry = 1000; - struct dc_link *link = NULL; - - if (!stream) - return false; - - link = dc_stream_get_link(stream); - - if (!link) - return false; - - if (!dc_link_set_replay_allow_active(link, &replay_active, false, force_static, NULL)) - return false; - - 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 */ - } - - return true; -} - -static unsigned int mod_power_replay_setup_power_opt(struct dc_link *link, - unsigned int active_replay_events, bool is_ultra_sleep_mode) -{ - unsigned int power_opt = 0; - - if (is_ultra_sleep_mode) { - /* Static Screen */ - power_opt |= (replay_power_opt_smu_opt_static_screen | replay_power_opt_z10_static_screen); - } else if (active_replay_events & replay_event_test_harness_ultra_sleep) { - power_opt |= replay_power_opt_z10_static_screen; - } - - /* replay_power_opt_flag is a configuration parameter into the module that determines - * which optimizations to enable during replay - */ - power_opt &= link->replay_settings.config.replay_power_opt_supported; - - return power_opt; -} - -static bool mod_power_replay_set_power_opt(struct mod_power *mod_power, - struct dc_stream_state *stream, - unsigned int active_replay_events, - bool is_ultra_sleep_mode) -{ - (void)mod_power; - struct dc_link *link = NULL; - unsigned int power_opt = 0; - - if (!stream) - return false; - - link = dc_stream_get_link(stream); - - if (!link || !link->replay_settings.replay_feature_enabled) - return false; - - power_opt = mod_power_replay_setup_power_opt(link, active_replay_events, is_ultra_sleep_mode); - - if (!dc_link_set_replay_allow_active(link, NULL, false, false, &power_opt)) - return false; - - return true; -} - -bool mod_power_get_replay_event(struct mod_power *mod_power, - struct dc_stream_state *stream, - unsigned int *active_replay_events) -{ - struct core_power *core_power = NULL; - unsigned int stream_index = 0; - - if (mod_power == NULL) - return false; - - core_power = MOD_POWER_TO_CORE(mod_power); - - if (core_power->num_entities == 0) - return false; - - stream_index = map_index_from_stream(core_power, stream); - - *active_replay_events = core_power->map[stream_index].replay_events; - - return true; -} - -static bool mod_power_update_replay_active_status(unsigned int active_replay_events, - struct dc_link *link, uint32_t *coasting_vtotal, bool *is_full_screen_video, bool *is_ultra_sleep_mode, uint16_t *frame_skip_number, bool *is_video_playback) -{ - if (!link || !coasting_vtotal || !is_full_screen_video || !is_video_playback) - return false; - - // Check coasting_vtotal_table has been updated. - if (!link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_STATIC] - || !link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_NOM]) - return false; - - unsigned int replay_enable_option = - link->replay_settings.config.replay_enable_option; - - /* TODO: To support test harness and DDS event */ - - *coasting_vtotal = link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_NOM]; - ASSERT(link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_NOM] <= 0xFFFF); - *frame_skip_number = (uint16_t)link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_NOM]; - - link->replay_settings.config.replay_timing_sync_supported = false; - - *is_full_screen_video = false; - - *is_ultra_sleep_mode = false; - - *is_video_playback = false; - - /* DSAT test scenario */ - if (active_replay_events & replay_event_test_harness_mode) { - if (link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_TEST_HARNESS]) - *coasting_vtotal = - link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_TEST_HARNESS]; - if (link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]) { - ASSERT(link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS] <= 0xFFFF); - *frame_skip_number = - (uint16_t)link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]; - } - - /* During the ultra sleep mode testing, disable the timing sync in short vblank mode */ - if (active_replay_events & (replay_event_test_harness_enable_replay)) { - if ((active_replay_events & replay_event_test_harness_ultra_sleep) && - !link->replay_settings.config.replay_support_fast_resync_in_ultra_sleep_mode) - link->replay_settings.config.replay_timing_sync_supported = false; - return true; - } else - return false; - } else if (active_replay_events & (replay_event_test_harness_enable_replay)) { - if (link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_TEST_HARNESS]) - *coasting_vtotal = link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_TEST_HARNESS]; - if (link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]) { - uint32_t frame_skip_val = - link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]; - - ASSERT(frame_skip_val <= 0xFFFF); - *frame_skip_number = (uint16_t)frame_skip_val; - } - - /* During the ultra sleep mode testing, disable the timing sync in short vblank mode */ - if ((active_replay_events & replay_event_test_harness_ultra_sleep) && - !link->replay_settings.config.replay_support_fast_resync_in_ultra_sleep_mode) - link->replay_settings.config.replay_timing_sync_supported = false; - return true; - } else if (active_replay_events & (replay_event_test_harness_disable_replay | replay_event_os_request_disable)) { - // set last set coasting vtotal - if (link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_TEST_HARNESS]) - *coasting_vtotal = link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_TEST_HARNESS]; - if (link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]) { - uint32_t frame_skip_val = - link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]; - - ASSERT(frame_skip_val <= 0xFFFF); - *frame_skip_number = (uint16_t)frame_skip_val; - } - return false; - } - - /* Inactive conditions */ - if (active_replay_events & (replay_event_edp_panel_off_disable_psr | - replay_event_hw_programming | - replay_event_vrr | - replay_event_immediate_flip | - replay_event_prepare_vtotal | - replay_event_vrr_transition | - replay_event_pause | - replay_event_disable_replay_while_DPMS | - replay_event_sleep_resume | - replay_event_disable_in_AC | - replay_event_disable_replay_while_detect_display | - replay_event_infopacket | - replay_event_crc_window_active)) - return false; - - // Full screen scenario - if (active_replay_events & replay_event_full_screen) { - if (!(replay_enable_option & pr_enable_option_full_screen)) - return false; - } - - /* Full screen video scenario */ - if (active_replay_events & replay_event_big_screen_video) { - - link->replay_settings.config.replay_timing_sync_supported = false; - - if (replay_enable_option & pr_enable_option_full_screen_video_coasting) { - unsigned int fsn_vid = - link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_FULL_SCREEN_VIDEO]; - - *coasting_vtotal = - link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_FULL_SCREEN_VIDEO]; - ASSERT(fsn_vid <= 0xFFFF); - *frame_skip_number = (uint16_t)fsn_vid; - } - - *is_video_playback = true; - - if ((replay_enable_option & pr_enable_option_full_screen_video) && - (replay_enable_option & pr_enable_option_full_screen_video_coasting)) { - *is_full_screen_video = true; - return true; - } else - return false; - } - - /* MPO video scenario - * Some of the cases may contain a full screen UI layer in MPO video scenario which is - * not the expected case to enable Replay. - */ - if ((active_replay_events & replay_event_mpo_video_selective_update) && - !(active_replay_events & replay_event_full_screen)) { - - link->replay_settings.config.replay_timing_sync_supported = false; - - if (replay_enable_option & pr_enable_option_mpo_video_coasting) { - *coasting_vtotal = link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_NOM]; - { - uint32_t frame_skip_val = - link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_NOM]; - - ASSERT(frame_skip_val <= 0xFFFF); - *frame_skip_number = (uint16_t)frame_skip_val; - } - } - - *is_video_playback = true; - - if (replay_enable_option & pr_enable_option_mpo_video) - return true; - else - return false; - } - - /* Static screen scenario */ - if (!(active_replay_events & replay_event_vsync)) { - - if (replay_enable_option & pr_enable_option_static_screen_coasting) { - // Do not adjust eDP refresh rate if static screen + normal sleep mode - if ((!(link->replay_settings.config.replay_power_opt_supported & - replay_power_opt_z10_static_screen)) || - (active_replay_events & replay_event_cursor_updating)) { - // normal sleep mode - *coasting_vtotal = - link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_NOM]; - { - uint32_t frame_skip_val = - link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_NOM]; - - ASSERT(frame_skip_val <= 0xFFFF); - *frame_skip_number = (uint16_t)frame_skip_val; - } - } else { - // ultra sleep mode - *coasting_vtotal = - link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_STATIC]; - { - uint32_t frame_skip_val = - link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_STATIC]; - - ASSERT(frame_skip_val <= 0xFFFF); - *frame_skip_number = (uint16_t)frame_skip_val; - } - *is_ultra_sleep_mode = true; - } - } - - if (replay_enable_option & pr_enable_option_static_screen) { - if (!link->replay_settings.config.replay_support_fast_resync_in_ultra_sleep_mode) - link->replay_settings.config.replay_timing_sync_supported = false; - return true; - } else - return false; - } - - /* General UI scenario */ - if (active_replay_events & replay_event_general_ui) { - if (replay_enable_option & pr_enable_option_general_ui) - return true; - else - return false; - } - - return false; -} - -bool mod_power_replay_set_coasting_vtotal(struct mod_power *mod_power, - const struct dc_stream_state *stream, - uint32_t coasting_vtotal, - uint16_t frame_skip_number) -{ - struct core_power *core_power = NULL; - struct dc_link *link = NULL; - - if (!stream) - return false; - - link = dc_stream_get_link(stream); - if (!link || !link->replay_settings.replay_feature_enabled) - return false; - - if (mod_power == NULL) - return false; - - core_power = MOD_POWER_TO_CORE(mod_power); - - if (core_power->num_entities == 0) - return false; - - return link->dc->link_srv->edp_set_coasting_vtotal(link, coasting_vtotal, frame_skip_number); -} - -void mod_power_replay_set_timing_sync_supported(struct mod_power *mod_power, - const struct dc_stream_state *stream) -{ - struct core_power *core_power = NULL; - struct dc_link *link = NULL; - unsigned int stream_index = 0; - union dmub_replay_cmd_set cmd_data = { 0 }; - - if (!stream || mod_power == NULL) - return; - - core_power = MOD_POWER_TO_CORE(mod_power); - if (core_power->num_entities == 0) - return; - - stream_index = map_index_from_stream(core_power, stream); - if (stream_index > core_power->num_entities) //invalid index - return; - - link = dc_stream_get_link(stream); - if (!link || !link->replay_settings.replay_feature_enabled) - return; - - cmd_data.sync_data.timing_sync_supported = link->replay_settings.config.replay_timing_sync_supported; - - link->dc->link_srv->edp_send_replay_cmd(link, Replay_Set_Timing_Sync_Supported, - &cmd_data); -} - -void mod_power_replay_disabled_adaptive_sync_sdp(struct mod_power *mod_power, - const struct dc_stream_state *stream, bool force_disabled) -{ - struct core_power *core_power = NULL; - struct dc_link *link = NULL; - unsigned int stream_index = 0; - union dmub_replay_cmd_set cmd_data = { 0 }; - - if (!stream || mod_power == NULL) - return; - - core_power = MOD_POWER_TO_CORE(mod_power); - if (core_power->num_entities == 0) - return; - - stream_index = map_index_from_stream(core_power, stream); - if (stream_index > core_power->num_entities) //invalid index - return; - - link = dc_stream_get_link(stream); - if (!link || !link->replay_settings.replay_feature_enabled) - return; - - cmd_data.disabled_adaptive_sync_sdp_data.force_disabled = force_disabled; - - link->dc->link_srv->edp_send_replay_cmd(link, Replay_Disabled_Adaptive_Sync_SDP, - &cmd_data); -} - -static void mod_power_replay_set_general_cmd(struct mod_power *mod_power, - const struct dc_stream_state *stream, - const enum dmub_cmd_replay_general_subtype general_cmd_type, - const uint32_t param1, const uint32_t param2) -{ - struct core_power *core_power = NULL; - struct dc_link *link = NULL; - unsigned int stream_index = 0; - union dmub_replay_cmd_set cmd_data = { 0 }; - - if (!stream || mod_power == NULL) - return; - - core_power = MOD_POWER_TO_CORE(mod_power); - if (core_power->num_entities == 0) - return; - - stream_index = map_index_from_stream(core_power, stream); - if (stream_index > core_power->num_entities) //invalid index - return; - - link = dc_stream_get_link(stream); - if (!link || !link->replay_settings.replay_feature_enabled) - return; - - cmd_data.set_general_cmd_data.subtype = general_cmd_type; - cmd_data.set_general_cmd_data.param1 = param1; - cmd_data.set_general_cmd_data.param2 = param2; - link->dc->link_srv->edp_send_replay_cmd(link, Replay_Set_General_Cmd, - &cmd_data); -} - -void mod_power_replay_disabled_desync_error_detection(struct mod_power *mod_power, - const struct dc_stream_state *stream, bool force_disabled) -{ - mod_power_replay_set_general_cmd(mod_power, stream, - REPLAY_GENERAL_CMD_DISABLED_DESYNC_ERROR_DETECTION, - force_disabled, 0); -} - -static void mod_power_replay_set_pseudo_vtotal(struct mod_power *mod_power, - const struct dc_stream_state *stream, uint16_t vtotal) -{ - struct core_power *core_power = NULL; - struct dc_link *link = NULL; - unsigned int stream_index = 0; - union dmub_replay_cmd_set cmd_data = { 0 }; - - if (!stream || mod_power == NULL) - return; - - core_power = MOD_POWER_TO_CORE(mod_power); - if (core_power->num_entities == 0) - return; - - stream_index = map_index_from_stream(core_power, stream); - if (stream_index > core_power->num_entities) //invalid index - return; - - link = dc_stream_get_link(stream); - if (!link || !link->replay_settings.replay_feature_enabled) - return; - - cmd_data.pseudo_vtotal_data.vtotal = vtotal; - - if (link->replay_settings.last_pseudo_vtotal != vtotal) { - link->replay_settings.last_pseudo_vtotal = vtotal; - link->dc->link_srv->edp_send_replay_cmd(link, Replay_Set_Pseudo_VTotal, &cmd_data); + /* Handle Replay notification */ + mod_power_replay_notify_mode_change(mod_power, dc, link, stream, stream_index); } -} - -static void mod_power_update_error_status(struct mod_power *mod_power, - const struct dc_stream_state *stream) -{ - struct dc_link *link = NULL; - union replay_debug_flags *pDebug = NULL; - - if (mod_power == NULL || stream == NULL) - return; - - link = dc_stream_get_link(stream); - - if (!link) - return; - - pDebug = (union replay_debug_flags *)&link->replay_settings.config.debug_flags; - - if (0 == pDebug->bitfields.enable_visual_confirm_debug) - return; - - mod_power_replay_set_general_cmd(mod_power, stream, - REPLAY_GENERAL_CMD_UPDATE_ERROR_STATUS, - link->replay_settings.config.replay_error_status.raw, 0); -} - -void mod_power_set_low_rr_activate(struct mod_power *mod_power, - const struct dc_stream_state *stream, bool low_rr_supported) -{ - struct dc_link *link = NULL; - - if (mod_power == NULL || stream == NULL) - return; - - link = dc_stream_get_link(stream); - - if (!link) - return; - - mod_power_replay_set_general_cmd(mod_power, stream, - REPLAY_GENERAL_CMD_SET_LOW_RR_ACTIVATE, - low_rr_supported, 0); -} - -void mod_power_set_video_conferencing_activate(struct mod_power *mod_power, - const struct dc_stream_state *stream, bool video_conferencing_activate) -{ - struct dc_link *link = NULL; - - if (mod_power == NULL || stream == NULL) - return; - - link = dc_stream_get_link(stream); - if (!link || !link->replay_settings.replay_feature_enabled) - return; - - mod_power_replay_set_general_cmd(mod_power, stream, - REPLAY_GENERAL_CMD_VIDEO_CONFERENCING, - video_conferencing_activate, 0); -} - -void mod_power_set_coasting_vtotal_without_frame_update(struct mod_power *mod_power, - const struct dc_stream_state *stream, uint32_t coasting_vtotal) -{ - struct dc_link *link = NULL; - - if (mod_power == NULL || stream == NULL) - return; - - link = dc_stream_get_link(stream); - if (!link || !link->replay_settings.replay_feature_enabled) - return; - - mod_power_replay_set_general_cmd(mod_power, stream, - REPLAY_GENERAL_CMD_SET_COASTING_VTOTAL_WITHOUT_FRAME_UPDATE, - coasting_vtotal, 0); -} - -void mod_power_set_replay_continuously_resync(struct mod_power *mod_power, - const struct dc_stream_state *stream, bool enable) -{ - struct dc_link *link = NULL; - - if (mod_power == NULL || stream == NULL) - return; - - link = dc_stream_get_link(stream); - if (!link || !link->replay_settings.replay_feature_enabled) - return; - - mod_power_replay_set_general_cmd(mod_power, stream, - REPLAY_GENERAL_CMD_SET_CONTINUOUSLY_RESYNC, - enable, 0); -} - -void mod_power_set_live_capture_with_cvt_activate(struct mod_power *mod_power, - const struct dc_stream_state *stream, bool live_capture_with_cvt_activate) -{ - struct dc_link *link = NULL; - - if (mod_power == NULL || stream == NULL) - return; - - link = dc_stream_get_link(stream); - if (!link || !link->replay_settings.replay_feature_enabled) - return; - - // Check if LIVE_CAPTURE_WITH_CVT bit is enabled in DalRegKey_ReplayOptimization - if (!link->replay_settings.config.replay_optimization.bits.LIVE_CAPTURE_WITH_CVT) - return; - - if (link->replay_settings.config.live_capture_with_cvt_activated != live_capture_with_cvt_activate) { - link->replay_settings.config.live_capture_with_cvt_activated = live_capture_with_cvt_activate; - mod_power_replay_set_general_cmd(mod_power, stream, - REPLAY_GENERAL_CMD_LIVE_CAPTURE_WITH_CVT, - live_capture_with_cvt_activate, 0); - } -} - -bool mod_power_set_replay_event(struct mod_power *mod_power, - struct dc_stream_state *stream, bool set_event, - enum replay_event event, bool wait_for_disable) -{ - struct core_power *core_power = NULL; - struct dc_link *link = NULL; - unsigned int stream_index = 0; - unsigned int active_replay_events = 0; - bool replay_active_request = false; - bool force_static = false; - uint32_t coasting_vtotal = 0; - bool current_timing_sync_status = false; - bool is_full_screen_video = false; - bool is_ultra_sleep_mode = false; - unsigned int sink_duration_us = 0; - bool low_rr_active = false; - uint16_t frame_skip_number = 0; - bool is_video_playback = false; - - if (!stream) - return false; - - if (mod_power == NULL) - return false; - - core_power = MOD_POWER_TO_CORE(mod_power); - - if (core_power->num_entities == 0) - return false; - - stream_index = map_index_from_stream(core_power, stream); - - if (set_event) - core_power->map[stream_index].replay_events |= event; - else - core_power->map[stream_index].replay_events &= ~event; - - link = dc_stream_get_link(stream); - if (!link || !link->replay_settings.replay_feature_enabled) - return false; - - if ((core_power->map[stream_index].replay_events & replay_event_disable_replay_while_switching_mux) != 0) - return false; - - if ((core_power->map[stream_index].replay_events & replay_event_os_override_hold) != 0) - return false; - - active_replay_events = core_power->map[stream_index].replay_events; - - current_timing_sync_status = - link->replay_settings.config.replay_timing_sync_supported; - - replay_active_request = mod_power_update_replay_active_status(active_replay_events, - link, &coasting_vtotal, &is_full_screen_video, &is_ultra_sleep_mode, &frame_skip_number, &is_video_playback); - - if (is_full_screen_video) - mod_power_replay_set_pseudo_vtotal(mod_power, stream, - link->replay_settings.low_rr_full_screen_video_pseudo_vtotal); - else - mod_power_replay_set_pseudo_vtotal(mod_power, stream, 0); - - //If timing_sync_status change, then re-enabled set timing_sync_supported value and re-enabled replay - if (current_timing_sync_status != link->replay_settings.config.replay_timing_sync_supported) - mod_power_replay_set_timing_sync_supported(mod_power, stream); - - if (link->replay_settings.config.low_rr_supported) { - sink_duration_us = - (unsigned int)(div_u64(((unsigned long long)(coasting_vtotal) - * 10000) * stream->timing.h_total, - stream->timing.pix_clk_100hz)); - low_rr_active = sink_duration_us < LOW_REFRESH_RATE_DURATION_US_UPPER_BOUND ? false : true; - if (low_rr_active != link->replay_settings.config.low_rr_activated) { - mod_power_set_low_rr_activate(mod_power, stream, low_rr_active); - link->replay_settings.config.low_rr_activated = low_rr_active; - } - } - - // The function return fail when - // 1. DMUB function is not support (for backward compatible). - // 2. active_replay_events or coasting_vtotal is not updated in the same time - if (!mod_power_replay_set_power_opt_and_coasting_vtotal(mod_power, - stream, active_replay_events, coasting_vtotal, is_ultra_sleep_mode, frame_skip_number)) { - if (!mod_power_replay_set_power_opt(mod_power, stream, active_replay_events, is_ultra_sleep_mode)) - return false; - - if (!mod_power_replay_set_coasting_vtotal(mod_power, stream, coasting_vtotal, frame_skip_number)) - return false; - } - - mod_power_set_live_capture_with_cvt_activate(mod_power, stream, is_video_playback); - - mod_power_update_error_status(mod_power, stream); - - // If Replay is going to be enable (No matter is disable -> enable or enable -> enable), we don't need to wait. - // If Replay is going to be disable - // if disable -> disable - // -> Replay DMUB state should be state 0. - // So no matter wait_for_disable is true or not, it should makes no difference. - // if enable -> disable -> We should wait if wait_for_disable is true. - if (replay_active_request) - wait_for_disable = false; - - if (!mod_power_set_replay_active(stream, replay_active_request, wait_for_disable, force_static)) - return false; return true; } - -bool mod_power_get_replay_active_status(const struct dc_stream_state *stream, - bool *replay_active) -{ - const struct dc_link *link = NULL; - - if (!stream) - return false; - - link = dc_stream_get_link(stream); - *replay_active = link->replay_settings.replay_allow_active; - - return true; -} - -void mod_power_replay_residency(const struct dc_stream_state *stream, - unsigned int *residency, const bool is_start, const bool is_alpm) -{ - const struct dc_link *link = NULL; - enum pr_residency_mode mode; - - if (!stream) - return; - - link = dc_stream_get_link(stream); - - if (is_alpm) - mode = PR_RESIDENCY_MODE_ALPM; - else - mode = PR_RESIDENCY_MODE_PHY; - - if (link && link->dc && link->dc->link_srv) - link->dc->link_srv->edp_replay_residency(link, residency, is_start, mode); -} - -bool mod_power_replay_set_power_opt_and_coasting_vtotal(struct mod_power *mod_power, - const struct dc_stream_state *stream, unsigned int active_replay_events, uint32_t coasting_vtotal, - bool is_ultra_sleep_mode, uint16_t frame_skip_number) -{ - struct core_power *core_power = NULL; - struct dc_link *link = NULL; - unsigned int power_opt = 0; - - if (!stream) - return false; - - if (mod_power == NULL) - return false; - - core_power = MOD_POWER_TO_CORE(mod_power); - - if (core_power->num_entities == 0) - return false; - - link = dc_stream_get_link(stream); - - if (!link || !link->replay_settings.replay_feature_enabled) - return false; - - power_opt = mod_power_replay_setup_power_opt(link, active_replay_events, is_ultra_sleep_mode); - - return link->dc->link_srv->edp_set_replay_power_opt_and_coasting_vtotal(link, &power_opt, coasting_vtotal, frame_skip_number); -} - - - - - diff --git a/drivers/gpu/drm/amd/display/modules/power/power_abm.c b/drivers/gpu/drm/amd/display/modules/power/power_abm.c index 8ed7ce26476e..b94dbb9e64a7 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_abm.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_abm.c @@ -245,8 +245,6 @@ struct iram_table_v_2_2 { #define MOD_POWER_TO_CORE(mod_power)\ container_of(mod_power, struct core_power, mod_public) - - static uint16_t backlight_8_to_16(unsigned int backlight_8bit) { return (uint16_t)(backlight_8bit * 0x101); diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c index 2fc2e2929e95..bf0c5901b4ee 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c @@ -33,99 +33,7 @@ #define bswap16_based_on_endian(big_endian, value) \ ((big_endian) ? cpu_to_be16(value) : cpu_to_le16(value)) -void init_replay_config(struct dc_link *link, struct replay_config *pr_config) -{ - link->replay_settings.config = *pr_config; -} - bool mod_power_only_edp(const struct dc_state *context, const struct dc_stream_state *stream) { return context && context->stream_count == 1 && dc_is_embedded_signal(stream->signal); } - -void set_replay_frame_skip_number(struct dc_link *link, - enum replay_coasting_vtotal_type type, - uint32_t coasting_vtotal_refresh_rate_uhz, - uint32_t flicker_free_refresh_rate_uhz, - bool is_defer) -{ - uint32_t *frame_skip_number_array = NULL; - uint32_t frame_skip_number = 0; - - if (link == NULL) - return; - - if (false == link->replay_settings.config.frame_skip_supported) - return; - - if (flicker_free_refresh_rate_uhz == 0 || coasting_vtotal_refresh_rate_uhz == 0) - return; - - if (is_defer) - frame_skip_number_array = link->replay_settings.defer_frame_skip_number_table; - else - frame_skip_number_array = link->replay_settings.frame_skip_number_table; - - if (frame_skip_number_array == NULL) - return; - - frame_skip_number = (coasting_vtotal_refresh_rate_uhz + 500000) / flicker_free_refresh_rate_uhz; - - if (frame_skip_number >= 1) - frame_skip_number_array[type] = frame_skip_number - 1; - else - frame_skip_number_array[type] = 0; -} - -void set_replay_defer_update_coasting_vtotal(struct dc_link *link, - enum replay_coasting_vtotal_type type, - uint32_t vtotal) -{ - link->replay_settings.defer_update_coasting_vtotal_table[type] = vtotal; -} - -void update_replay_coasting_vtotal_from_defer(struct dc_link *link, - enum replay_coasting_vtotal_type type) -{ - link->replay_settings.coasting_vtotal_table[type] = - link->replay_settings.defer_update_coasting_vtotal_table[type]; - link->replay_settings.frame_skip_number_table[type] = - link->replay_settings.defer_frame_skip_number_table[type]; -} - -void set_replay_coasting_vtotal(struct dc_link *link, - enum replay_coasting_vtotal_type type, - uint32_t vtotal) -{ - link->replay_settings.coasting_vtotal_table[type] = vtotal; -} - -void set_replay_low_rr_full_screen_video_src_vtotal(struct dc_link *link, uint16_t vtotal) -{ - link->replay_settings.low_rr_full_screen_video_pseudo_vtotal = vtotal; -} - -void calculate_replay_link_off_frame_count(struct dc_link *link, - uint16_t vtotal, uint16_t htotal) -{ - uint32_t max_link_off_frame_count = 0; - uint16_t max_deviation_line = 0, pixel_deviation_per_line = 0; - - if (!link || link->replay_settings.config.replay_version != DC_FREESYNC_REPLAY) - return; - - max_deviation_line = link->dpcd_caps.pr_info.max_deviation_line; - pixel_deviation_per_line = link->dpcd_caps.pr_info.pixel_deviation_per_line; - - if (htotal != 0 && vtotal != 0 && pixel_deviation_per_line != 0) - max_link_off_frame_count = htotal * max_deviation_line / (pixel_deviation_per_line * vtotal); - else - ASSERT(0); - - link->replay_settings.link_off_frame_count = max_link_off_frame_count; -} - -void reset_replay_dsync_error_count(struct dc_link *link) -{ - link->replay_settings.replay_desync_error_fail_count = 0; -} diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h index 3a2ba87be706..600da3e33126 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h @@ -203,4 +203,9 @@ bool mod_power_psr_notify_mode_change(struct mod_power *mod_power, const struct dc_stream_state *stream, struct dc_link *link, unsigned int stream_index); +void mod_power_replay_notify_mode_change(struct mod_power *mod_power, + struct dc *dc, + struct dc_link *link, + const struct dc_stream_state *stream, + unsigned int stream_index); #endif /* MODULES_POWER_POWER_HELPERS_H_ */ diff --git a/drivers/gpu/drm/amd/display/modules/power/power_replay.c b/drivers/gpu/drm/amd/display/modules/power/power_replay.c new file mode 100644 index 000000000000..983be9759e74 --- /dev/null +++ b/drivers/gpu/drm/amd/display/modules/power/power_replay.c @@ -0,0 +1,911 @@ +// SPDX-License-Identifier: MIT +// +// Copyright 2026 Advanced Micro Devices, Inc. + +#include "dm_services.h" +#include "dc.h" +#include "mod_power.h" +#include "core_types.h" +#include "dmcu.h" +#include "abm.h" +#include "power_helpers.h" +#include "dce/dmub_psr.h" +#include "dal_asic_id.h" +#include "link_service.h" +#include <linux/math.h> + +#define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */ +#define DC_TRACE_LEVEL_MESSAGEP(...) /* do nothing */ +#include "power_helpers.h" +#include "dc/inc/hw/dmcu.h" +#include "dc/inc/hw/abm.h" +#include "dc.h" +#include "core_types.h" +#include "dmub_cmd.h" + +#define MOD_POWER_TO_CORE(mod_power)\ + container_of(mod_power, struct core_power, mod_public) + +#define LOW_REFRESH_RATE_DURATION_US_UPPER_BOUND 25000 + +static bool mod_power_set_replay_active(struct dc_stream_state *stream, + bool replay_active, + bool wait, + bool force_static) +{ + uint64_t state; + unsigned int retry_count; + const unsigned int max_retry = 1000; + struct dc_link *link = NULL; + + if (!stream) + return false; + + link = dc_stream_get_link(stream); + + if (!link) + return false; + + if (!dc_link_set_replay_allow_active(link, &replay_active, false, force_static, NULL)) + return false; + + 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 */ + } + + return true; +} + +static unsigned int mod_power_replay_setup_power_opt(struct dc_link *link, + unsigned int active_replay_events, bool is_ultra_sleep_mode) +{ + unsigned int power_opt = 0; + + if (is_ultra_sleep_mode) { + /* Static Screen */ + power_opt |= (replay_power_opt_smu_opt_static_screen | replay_power_opt_z10_static_screen); + } else if (active_replay_events & replay_event_test_harness_ultra_sleep) { + power_opt |= replay_power_opt_z10_static_screen; + } + + /* replay_power_opt_flag is a configuration parameter into the module that determines + * which optimizations to enable during replay + */ + power_opt &= link->replay_settings.config.replay_power_opt_supported; + + return power_opt; +} + +static bool mod_power_replay_set_power_opt(struct mod_power *mod_power, + struct dc_stream_state *stream, + unsigned int active_replay_events, + bool is_ultra_sleep_mode) +{ + (void)mod_power; + struct dc_link *link = NULL; + unsigned int power_opt = 0; + + if (!stream) + return false; + + link = dc_stream_get_link(stream); + + if (!link || !link->replay_settings.replay_feature_enabled) + return false; + + power_opt = mod_power_replay_setup_power_opt(link, active_replay_events, is_ultra_sleep_mode); + + if (!dc_link_set_replay_allow_active(link, NULL, false, false, &power_opt)) + return false; + + return true; +} + +bool mod_power_get_replay_event(struct mod_power *mod_power, + struct dc_stream_state *stream, + unsigned int *active_replay_events) +{ + struct core_power *core_power = NULL; + unsigned int stream_index = 0; + + if (mod_power == NULL) + return false; + + core_power = MOD_POWER_TO_CORE(mod_power); + + if (core_power->num_entities == 0) + return false; + + stream_index = map_index_from_stream(core_power, stream); + + *active_replay_events = core_power->map[stream_index].replay_events; + + return true; +} + +static bool mod_power_update_replay_active_status(unsigned int active_replay_events, + struct dc_link *link, uint32_t *coasting_vtotal, bool *is_full_screen_video, + bool *is_ultra_sleep_mode, uint16_t *frame_skip_number, bool *is_video_playback) +{ + if (!link || !coasting_vtotal || !is_full_screen_video || !is_video_playback) + return false; + + // Check coasting_vtotal_table has been updated. + if (!link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_STATIC] + || !link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_NOM]) + return false; + + unsigned int replay_enable_option = + link->replay_settings.config.replay_enable_option; + + /* TODO: To support test harness and DDS event */ + + *coasting_vtotal = link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_NOM]; + ASSERT(link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_NOM] <= 0xFFFF); + *frame_skip_number = (uint16_t)link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_NOM]; + + link->replay_settings.config.replay_timing_sync_supported = false; + + *is_full_screen_video = false; + + *is_ultra_sleep_mode = false; + + *is_video_playback = false; + + /* DSAT test scenario */ + if (active_replay_events & replay_event_test_harness_mode) { + if (link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_TEST_HARNESS]) + *coasting_vtotal = + link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_TEST_HARNESS]; + if (link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]) { + ASSERT(link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS] <= 0xFFFF); + *frame_skip_number = + (uint16_t)link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]; + } + + /* During the ultra sleep mode testing, disable the timing sync in short vblank mode */ + if (active_replay_events & (replay_event_test_harness_enable_replay)) { + if ((active_replay_events & replay_event_test_harness_ultra_sleep) && + !link->replay_settings.config.replay_support_fast_resync_in_ultra_sleep_mode) + link->replay_settings.config.replay_timing_sync_supported = false; + return true; + } else + return false; + } else if (active_replay_events & (replay_event_test_harness_enable_replay)) { + if (link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_TEST_HARNESS]) + *coasting_vtotal = link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_TEST_HARNESS]; + if (link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]) { + uint32_t frame_skip_val = + link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]; + + ASSERT(frame_skip_val <= 0xFFFF); + *frame_skip_number = (uint16_t)frame_skip_val; + } + + /* During the ultra sleep mode testing, disable the timing sync in short vblank mode */ + if ((active_replay_events & replay_event_test_harness_ultra_sleep) && + !link->replay_settings.config.replay_support_fast_resync_in_ultra_sleep_mode) { + link->replay_settings.config.replay_timing_sync_supported = false; + } + return true; + } else if (active_replay_events & + (replay_event_test_harness_disable_replay | replay_event_os_request_disable)) { + // set last set coasting vtotal + if (link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_TEST_HARNESS]) + *coasting_vtotal = link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_TEST_HARNESS]; + if (link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]) { + uint32_t frame_skip_val = + link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]; + + ASSERT(frame_skip_val <= 0xFFFF); + *frame_skip_number = (uint16_t)frame_skip_val; + } + return false; + } + + /* Inactive conditions */ + if (active_replay_events & (replay_event_edp_panel_off_disable_psr | + replay_event_hw_programming | + replay_event_vrr | + replay_event_immediate_flip | + replay_event_prepare_vtotal | + replay_event_vrr_transition | + replay_event_pause | + replay_event_disable_replay_while_DPMS | + replay_event_sleep_resume | + replay_event_disable_in_AC | + replay_event_disable_replay_while_detect_display | + replay_event_infopacket | + replay_event_crc_window_active)) + return false; + + // Full screen scenario + if (active_replay_events & replay_event_full_screen) { + if (!(replay_enable_option & pr_enable_option_full_screen)) + return false; + } + + /* Full screen video scenario */ + if (active_replay_events & replay_event_big_screen_video) { + + link->replay_settings.config.replay_timing_sync_supported = false; + + if (replay_enable_option & pr_enable_option_full_screen_video_coasting) { + unsigned int fsn_vid = + link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_FULL_SCREEN_VIDEO]; + + *coasting_vtotal = + link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_FULL_SCREEN_VIDEO]; + ASSERT(fsn_vid <= 0xFFFF); + *frame_skip_number = (uint16_t)fsn_vid; + } + + *is_video_playback = true; + + if ((replay_enable_option & pr_enable_option_full_screen_video) && + (replay_enable_option & pr_enable_option_full_screen_video_coasting)) { + *is_full_screen_video = true; + return true; + } else + return false; + } + + /* MPO video scenario + * Some of the cases may contain a full screen UI layer in MPO video scenario which is + * not the expected case to enable Replay. + */ + if ((active_replay_events & replay_event_mpo_video_selective_update) && + !(active_replay_events & replay_event_full_screen)) { + + link->replay_settings.config.replay_timing_sync_supported = false; + + if (replay_enable_option & pr_enable_option_mpo_video_coasting) { + *coasting_vtotal = link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_NOM]; + { + uint32_t frame_skip_val = + link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_NOM]; + + ASSERT(frame_skip_val <= 0xFFFF); + *frame_skip_number = (uint16_t)frame_skip_val; + } + } + + *is_video_playback = true; + + if (replay_enable_option & pr_enable_option_mpo_video) + return true; + else + return false; + } + + /* Static screen scenario */ + if (!(active_replay_events & replay_event_vsync)) { + + if (replay_enable_option & pr_enable_option_static_screen_coasting) { + // Do not adjust eDP refresh rate if static screen + normal sleep mode + if ((!(link->replay_settings.config.replay_power_opt_supported & + replay_power_opt_z10_static_screen)) || + (active_replay_events & replay_event_cursor_updating)) { + // normal sleep mode + *coasting_vtotal = + link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_NOM]; + { + uint32_t frame_skip_val = + link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_NOM]; + + ASSERT(frame_skip_val <= 0xFFFF); + *frame_skip_number = (uint16_t)frame_skip_val; + } + } else { + // ultra sleep mode + *coasting_vtotal = + link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_STATIC]; + { + uint32_t frame_skip_val = + link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_STATIC]; + + ASSERT(frame_skip_val <= 0xFFFF); + *frame_skip_number = (uint16_t)frame_skip_val; + } + *is_ultra_sleep_mode = true; + } + } + + if (replay_enable_option & pr_enable_option_static_screen) { + if (!link->replay_settings.config.replay_support_fast_resync_in_ultra_sleep_mode) + link->replay_settings.config.replay_timing_sync_supported = false; + return true; + } else + return false; + } + + /* General UI scenario */ + if (active_replay_events & replay_event_general_ui) { + if (replay_enable_option & pr_enable_option_general_ui) + return true; + else + return false; + } + + return false; +} + +bool mod_power_replay_set_coasting_vtotal(struct mod_power *mod_power, + const struct dc_stream_state *stream, + uint32_t coasting_vtotal, + uint16_t frame_skip_number) +{ + struct core_power *core_power = NULL; + struct dc_link *link = NULL; + + if (!stream) + return false; + + link = dc_stream_get_link(stream); + if (!link || !link->replay_settings.replay_feature_enabled) + return false; + + if (mod_power == NULL) + return false; + + core_power = MOD_POWER_TO_CORE(mod_power); + + if (core_power->num_entities == 0) + return false; + + return link->dc->link_srv->edp_set_coasting_vtotal(link, coasting_vtotal, frame_skip_number); +} + +void mod_power_replay_set_timing_sync_supported(struct mod_power *mod_power, + const struct dc_stream_state *stream) +{ + struct core_power *core_power = NULL; + struct dc_link *link = NULL; + unsigned int stream_index = 0; + union dmub_replay_cmd_set cmd_data = { 0 }; + + if (!stream || mod_power == NULL) + return; + + core_power = MOD_POWER_TO_CORE(mod_power); + if (core_power->num_entities == 0) + return; + + stream_index = map_index_from_stream(core_power, stream); + if (stream_index > core_power->num_entities) //invalid index + return; + + link = dc_stream_get_link(stream); + if (!link || !link->replay_settings.replay_feature_enabled) + return; + + cmd_data.sync_data.timing_sync_supported = link->replay_settings.config.replay_timing_sync_supported; + + link->dc->link_srv->edp_send_replay_cmd(link, Replay_Set_Timing_Sync_Supported, + &cmd_data); +} + +void mod_power_replay_disabled_adaptive_sync_sdp(struct mod_power *mod_power, + const struct dc_stream_state *stream, bool force_disabled) +{ + struct core_power *core_power = NULL; + struct dc_link *link = NULL; + unsigned int stream_index = 0; + union dmub_replay_cmd_set cmd_data = { 0 }; + + if (!stream || mod_power == NULL) + return; + + core_power = MOD_POWER_TO_CORE(mod_power); + if (core_power->num_entities == 0) + return; + + stream_index = map_index_from_stream(core_power, stream); + if (stream_index > core_power->num_entities) //invalid index + return; + + link = dc_stream_get_link(stream); + if (!link || !link->replay_settings.replay_feature_enabled) + return; + + cmd_data.disabled_adaptive_sync_sdp_data.force_disabled = force_disabled; + + link->dc->link_srv->edp_send_replay_cmd(link, Replay_Disabled_Adaptive_Sync_SDP, + &cmd_data); +} + +static void mod_power_replay_set_general_cmd(struct mod_power *mod_power, + const struct dc_stream_state *stream, + const enum dmub_cmd_replay_general_subtype general_cmd_type, + const uint32_t param1, const uint32_t param2) +{ + struct core_power *core_power = NULL; + struct dc_link *link = NULL; + unsigned int stream_index = 0; + union dmub_replay_cmd_set cmd_data = { 0 }; + + if (!stream || mod_power == NULL) + return; + + core_power = MOD_POWER_TO_CORE(mod_power); + if (core_power->num_entities == 0) + return; + + stream_index = map_index_from_stream(core_power, stream); + if (stream_index > core_power->num_entities) //invalid index + return; + + link = dc_stream_get_link(stream); + if (!link || !link->replay_settings.replay_feature_enabled) + return; + + cmd_data.set_general_cmd_data.subtype = general_cmd_type; + cmd_data.set_general_cmd_data.param1 = param1; + cmd_data.set_general_cmd_data.param2 = param2; + link->dc->link_srv->edp_send_replay_cmd(link, Replay_Set_General_Cmd, + &cmd_data); +} + +void mod_power_replay_disabled_desync_error_detection(struct mod_power *mod_power, + const struct dc_stream_state *stream, bool force_disabled) +{ + mod_power_replay_set_general_cmd(mod_power, stream, + REPLAY_GENERAL_CMD_DISABLED_DESYNC_ERROR_DETECTION, + force_disabled, 0); +} + +static void mod_power_replay_set_pseudo_vtotal(struct mod_power *mod_power, + const struct dc_stream_state *stream, uint16_t vtotal) +{ + struct core_power *core_power = NULL; + struct dc_link *link = NULL; + unsigned int stream_index = 0; + union dmub_replay_cmd_set cmd_data = { 0 }; + + if (!stream || mod_power == NULL) + return; + + core_power = MOD_POWER_TO_CORE(mod_power); + if (core_power->num_entities == 0) + return; + + stream_index = map_index_from_stream(core_power, stream); + if (stream_index > core_power->num_entities) //invalid index + return; + + link = dc_stream_get_link(stream); + if (!link || !link->replay_settings.replay_feature_enabled) + return; + + cmd_data.pseudo_vtotal_data.vtotal = vtotal; + + if (link->replay_settings.last_pseudo_vtotal != vtotal) { + link->replay_settings.last_pseudo_vtotal = vtotal; + link->dc->link_srv->edp_send_replay_cmd(link, Replay_Set_Pseudo_VTotal, &cmd_data); + } +} + +static void mod_power_update_error_status(struct mod_power *mod_power, + const struct dc_stream_state *stream) +{ + struct dc_link *link = NULL; + union replay_debug_flags *pDebug = NULL; + + if (mod_power == NULL || stream == NULL) + return; + + link = dc_stream_get_link(stream); + + if (!link) + return; + + pDebug = (union replay_debug_flags *)&link->replay_settings.config.debug_flags; + + if (pDebug->bitfields.enable_visual_confirm_debug == 0) + return; + + mod_power_replay_set_general_cmd(mod_power, stream, + REPLAY_GENERAL_CMD_UPDATE_ERROR_STATUS, + link->replay_settings.config.replay_error_status.raw, 0); +} + +void mod_power_set_low_rr_activate(struct mod_power *mod_power, + const struct dc_stream_state *stream, bool low_rr_supported) +{ + struct dc_link *link = NULL; + + if (mod_power == NULL || stream == NULL) + return; + + link = dc_stream_get_link(stream); + + if (!link) + return; + + mod_power_replay_set_general_cmd(mod_power, stream, + REPLAY_GENERAL_CMD_SET_LOW_RR_ACTIVATE, + low_rr_supported, 0); +} + +void mod_power_set_video_conferencing_activate(struct mod_power *mod_power, + const struct dc_stream_state *stream, bool video_conferencing_activate) +{ + struct dc_link *link = NULL; + + if (mod_power == NULL || stream == NULL) + return; + + link = dc_stream_get_link(stream); + if (!link || !link->replay_settings.replay_feature_enabled) + return; + + mod_power_replay_set_general_cmd(mod_power, stream, + REPLAY_GENERAL_CMD_VIDEO_CONFERENCING, + video_conferencing_activate, 0); +} + +void mod_power_set_coasting_vtotal_without_frame_update(struct mod_power *mod_power, + const struct dc_stream_state *stream, uint32_t coasting_vtotal) +{ + struct dc_link *link = NULL; + + if (mod_power == NULL || stream == NULL) + return; + + link = dc_stream_get_link(stream); + if (!link || !link->replay_settings.replay_feature_enabled) + return; + + mod_power_replay_set_general_cmd(mod_power, stream, + REPLAY_GENERAL_CMD_SET_COASTING_VTOTAL_WITHOUT_FRAME_UPDATE, + coasting_vtotal, 0); +} + +void mod_power_set_replay_continuously_resync(struct mod_power *mod_power, + const struct dc_stream_state *stream, bool enable) +{ + struct dc_link *link = NULL; + + if (mod_power == NULL || stream == NULL) + return; + + link = dc_stream_get_link(stream); + if (!link || !link->replay_settings.replay_feature_enabled) + return; + + mod_power_replay_set_general_cmd(mod_power, stream, + REPLAY_GENERAL_CMD_SET_CONTINUOUSLY_RESYNC, + enable, 0); +} + +void mod_power_set_live_capture_with_cvt_activate(struct mod_power *mod_power, + const struct dc_stream_state *stream, bool live_capture_with_cvt_activate) +{ + struct dc_link *link = NULL; + + if (mod_power == NULL || stream == NULL) + return; + + link = dc_stream_get_link(stream); + if (!link || !link->replay_settings.replay_feature_enabled) + return; + + // Check if LIVE_CAPTURE_WITH_CVT bit is enabled in replay optimization config + if (!link->replay_settings.config.replay_optimization.bits.LIVE_CAPTURE_WITH_CVT) + return; + + if (link->replay_settings.config.live_capture_with_cvt_activated != live_capture_with_cvt_activate) { + link->replay_settings.config.live_capture_with_cvt_activated = live_capture_with_cvt_activate; + mod_power_replay_set_general_cmd(mod_power, stream, + REPLAY_GENERAL_CMD_LIVE_CAPTURE_WITH_CVT, + live_capture_with_cvt_activate, 0); + } +} + +bool mod_power_set_replay_event(struct mod_power *mod_power, + struct dc_stream_state *stream, bool set_event, + enum replay_event event, bool wait_for_disable) +{ + struct core_power *core_power = NULL; + struct dc_link *link = NULL; + unsigned int stream_index = 0; + unsigned int active_replay_events = 0; + bool replay_active_request = false; + bool force_static = false; + uint32_t coasting_vtotal = 0; + bool current_timing_sync_status = false; + bool is_full_screen_video = false; + bool is_ultra_sleep_mode = false; + unsigned int sink_duration_us = 0; + bool low_rr_active = false; + uint16_t frame_skip_number = 0; + bool is_video_playback = false; + + if (!stream) + return false; + + if (mod_power == NULL) + return false; + + core_power = MOD_POWER_TO_CORE(mod_power); + + if (core_power->num_entities == 0) + return false; + + stream_index = map_index_from_stream(core_power, stream); + + if (set_event) + core_power->map[stream_index].replay_events |= event; + else + core_power->map[stream_index].replay_events &= ~event; + + link = dc_stream_get_link(stream); + if (!link || !link->replay_settings.replay_feature_enabled) + return false; + + if ((core_power->map[stream_index].replay_events & replay_event_disable_replay_while_switching_mux) != 0) + return false; + + if ((core_power->map[stream_index].replay_events & replay_event_os_override_hold) != 0) + return false; + + active_replay_events = core_power->map[stream_index].replay_events; + + current_timing_sync_status = + link->replay_settings.config.replay_timing_sync_supported; + + replay_active_request = mod_power_update_replay_active_status(active_replay_events, + link, &coasting_vtotal, &is_full_screen_video, &is_ultra_sleep_mode, &frame_skip_number, &is_video_playback); + + if (is_full_screen_video) + mod_power_replay_set_pseudo_vtotal(mod_power, stream, + link->replay_settings.low_rr_full_screen_video_pseudo_vtotal); + else + mod_power_replay_set_pseudo_vtotal(mod_power, stream, 0); + + //If timing_sync_status change, then re-enabled set timing_sync_supported value and re-enabled replay + if (current_timing_sync_status != link->replay_settings.config.replay_timing_sync_supported) + mod_power_replay_set_timing_sync_supported(mod_power, stream); + + if (link->replay_settings.config.low_rr_supported) { + sink_duration_us = + (unsigned int)(div_u64(((unsigned long long)(coasting_vtotal) + * 10000) * stream->timing.h_total, + stream->timing.pix_clk_100hz)); + low_rr_active = sink_duration_us < LOW_REFRESH_RATE_DURATION_US_UPPER_BOUND ? false : true; + if (low_rr_active != link->replay_settings.config.low_rr_activated) { + mod_power_set_low_rr_activate(mod_power, stream, low_rr_active); + link->replay_settings.config.low_rr_activated = low_rr_active; + } + } + + // The function return fail when + // 1. DMUB function is not support (for backward compatible). + // 2. active_replay_events or coasting_vtotal is not updated in the same time + if (!mod_power_replay_set_power_opt_and_coasting_vtotal(mod_power, + stream, active_replay_events, coasting_vtotal, is_ultra_sleep_mode, frame_skip_number)) { + if (!mod_power_replay_set_power_opt(mod_power, stream, active_replay_events, is_ultra_sleep_mode)) + return false; + + if (!mod_power_replay_set_coasting_vtotal(mod_power, stream, coasting_vtotal, frame_skip_number)) + return false; + } + + mod_power_set_live_capture_with_cvt_activate(mod_power, stream, is_video_playback); + + mod_power_update_error_status(mod_power, stream); + + // If Replay is going to be enable (No matter is disable -> enable or enable -> enable), we don't need to wait. + // If Replay is going to be disable + // if disable -> disable + // -> Replay DMUB state should be state 0. + // So no matter wait_for_disable is true or not, it should makes no difference. + // if enable -> disable -> We should wait if wait_for_disable is true. + if (replay_active_request) + wait_for_disable = false; + + if (!mod_power_set_replay_active(stream, replay_active_request, wait_for_disable, force_static)) + return false; + + return true; +} + +bool mod_power_get_replay_active_status(const struct dc_stream_state *stream, + bool *replay_active) +{ + const struct dc_link *link = NULL; + + if (!stream) + return false; + + link = dc_stream_get_link(stream); + *replay_active = link->replay_settings.replay_allow_active; + + return true; +} + +void mod_power_replay_residency(const struct dc_stream_state *stream, + unsigned int *residency, const bool is_start, const bool is_alpm) +{ + const struct dc_link *link = NULL; + enum pr_residency_mode mode; + + if (!stream) + return; + + link = dc_stream_get_link(stream); + + if (is_alpm) + mode = PR_RESIDENCY_MODE_ALPM; + else + mode = PR_RESIDENCY_MODE_PHY; + + if (link && link->dc && link->dc->link_srv) + link->dc->link_srv->edp_replay_residency(link, residency, is_start, mode); +} + +bool mod_power_replay_set_power_opt_and_coasting_vtotal(struct mod_power *mod_power, + const struct dc_stream_state *stream, unsigned int active_replay_events, uint32_t coasting_vtotal, + bool is_ultra_sleep_mode, uint16_t frame_skip_number) +{ + struct core_power *core_power = NULL; + struct dc_link *link = NULL; + unsigned int power_opt = 0; + + if (!stream) + return false; + + if (mod_power == NULL) + return false; + + core_power = MOD_POWER_TO_CORE(mod_power); + + if (core_power->num_entities == 0) + return false; + + link = dc_stream_get_link(stream); + + if (!link || !link->replay_settings.replay_feature_enabled) + return false; + + power_opt = mod_power_replay_setup_power_opt(link, active_replay_events, is_ultra_sleep_mode); + + return link->dc->link_srv->edp_set_replay_power_opt_and_coasting_vtotal(link, &power_opt, coasting_vtotal, frame_skip_number); +} + +void mod_power_replay_notify_mode_change(struct mod_power *mod_power, + struct dc *dc, + struct dc_link *link, + const struct dc_stream_state *stream, + unsigned int stream_index) +{ + struct core_power *core_power = NULL; + int active_replay_events = 0; + + if (!mod_power || !dc || !link || !stream) + return; + + core_power = MOD_POWER_TO_CORE(mod_power); + active_replay_events = core_power->map[stream_index].replay_events; + + link->replay_settings.replay_smu_opt_enable = + (link->replay_settings.config.replay_smu_opt_supported && + mod_power_only_edp(dc->current_state, stream)); + + if (active_replay_events & replay_event_os_request_force_ffu) { + link->replay_settings.config.os_request_force_ffu = true; + } + + if (dc_is_embedded_signal(stream->signal)) + dc->link_srv->dp_setup_replay(link, stream); +} + +void init_replay_config(struct dc_link *link, struct replay_config *pr_config) +{ + link->replay_settings.config = *pr_config; +} + +void set_replay_frame_skip_number(struct dc_link *link, + enum replay_coasting_vtotal_type type, + uint32_t coasting_vtotal_refresh_rate_uhz, + uint32_t flicker_free_refresh_rate_uhz, + bool is_defer) +{ + uint32_t *frame_skip_number_array = NULL; + uint32_t frame_skip_number = 0; + + if (link == NULL) + return; + + if (link->replay_settings.config.frame_skip_supported == false) + return; + + if (flicker_free_refresh_rate_uhz == 0 || coasting_vtotal_refresh_rate_uhz == 0) + return; + + if (is_defer) + frame_skip_number_array = link->replay_settings.defer_frame_skip_number_table; + else + frame_skip_number_array = link->replay_settings.frame_skip_number_table; + + if (frame_skip_number_array == NULL) + return; + + frame_skip_number = (coasting_vtotal_refresh_rate_uhz + 500000) / flicker_free_refresh_rate_uhz; + + if (frame_skip_number >= 1) + frame_skip_number_array[type] = frame_skip_number - 1; + else + frame_skip_number_array[type] = 0; +} + +void set_replay_defer_update_coasting_vtotal(struct dc_link *link, + enum replay_coasting_vtotal_type type, + uint32_t vtotal) +{ + link->replay_settings.defer_update_coasting_vtotal_table[type] = vtotal; +} + +void update_replay_coasting_vtotal_from_defer(struct dc_link *link, + enum replay_coasting_vtotal_type type) +{ + link->replay_settings.coasting_vtotal_table[type] = + link->replay_settings.defer_update_coasting_vtotal_table[type]; + link->replay_settings.frame_skip_number_table[type] = + link->replay_settings.defer_frame_skip_number_table[type]; +} + +void set_replay_coasting_vtotal(struct dc_link *link, + enum replay_coasting_vtotal_type type, + uint32_t vtotal) +{ + link->replay_settings.coasting_vtotal_table[type] = vtotal; +} + +void set_replay_low_rr_full_screen_video_src_vtotal(struct dc_link *link, uint16_t vtotal) +{ + link->replay_settings.low_rr_full_screen_video_pseudo_vtotal = vtotal; +} + +void calculate_replay_link_off_frame_count(struct dc_link *link, + uint16_t vtotal, uint16_t htotal) +{ + uint32_t max_link_off_frame_count = 0; + uint16_t max_deviation_line = 0, pixel_deviation_per_line = 0; + + if (!link || link->replay_settings.config.replay_version != DC_FREESYNC_REPLAY) + return; + + max_deviation_line = link->dpcd_caps.pr_info.max_deviation_line; + pixel_deviation_per_line = link->dpcd_caps.pr_info.pixel_deviation_per_line; + + if (htotal != 0 && vtotal != 0 && pixel_deviation_per_line != 0) + max_link_off_frame_count = htotal * max_deviation_line / (pixel_deviation_per_line * vtotal); + else + ASSERT(0); + + link->replay_settings.link_off_frame_count = max_link_off_frame_count; +} + +void reset_replay_dsync_error_count(struct dc_link *link) +{ + link->replay_settings.replay_desync_error_fail_count = 0; +} -- 2.43.0
