# 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
return true;
}
-
bool mod_power_notify_mode_change(struct mod_power *mod_power,
const struct dc_stream_state *stream,
bool is_hdr)
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;
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;
/* 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);
-}
-
-
-
-
-
#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);
#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;
-}
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_ */
--- /dev/null
+// 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;
+}