drm/amd/display: Add some functions for Panel Replay
authorTom Chung <chiahsuan.chung@amd.com>
Fri, 1 Dec 2023 06:15:45 +0000 (14:15 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 3 Jan 2024 16:16:05 +0000 (11:16 -0500)
[WHY]
Prepare for enabling the Panel Replay feature

[HOW]
- Add some Panel Replay setting functions in DC
- Add the Panel Replay resource in dcn35_resource.c
- Add debug masks for Panel Replay

Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Acked-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
Reviewed-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: Tom Chung <chiahsuan.chung@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
13 files changed:
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c
drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h
drivers/gpu/drm/amd/display/dc/inc/link.h
drivers/gpu/drm/amd/display/dc/link/link_factory.c
drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h
drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c
drivers/gpu/drm/amd/display/modules/power/power_helpers.c
drivers/gpu/drm/amd/display/modules/power/power_helpers.h
drivers/gpu/drm/amd/include/amd_shared.h

index b7c2eaebf8bfde70cd2b95c7f0910c6429a2e5c6..2d7205058c64abfece9cd154a4aebea8958e0168 100644 (file)
@@ -4770,6 +4770,38 @@ bool dc_set_psr_allow_active(struct dc *dc, bool enable)
        return true;
 }
 
+/* enable/disable eDP Replay without specify stream for eDP */
+bool dc_set_replay_allow_active(struct dc *dc, bool active)
+{
+       int i;
+       bool allow_active;
+
+       for (i = 0; i < dc->current_state->stream_count; i++) {
+               struct dc_link *link;
+               struct dc_stream_state *stream = dc->current_state->streams[i];
+
+               link = stream->link;
+               if (!link)
+                       continue;
+
+               if (link->replay_settings.replay_feature_enabled) {
+                       if (active && !link->replay_settings.replay_allow_active) {
+                               allow_active = true;
+                               if (!dc_link_set_replay_allow_active(link, &allow_active,
+                                       false, false, NULL))
+                                       return false;
+                       } else if (!active && link->replay_settings.replay_allow_active) {
+                               allow_active = false;
+                               if (!dc_link_set_replay_allow_active(link, &allow_active,
+                                       true, false, NULL))
+                                       return false;
+                       }
+               }
+       }
+
+       return true;
+}
+
 void dc_allow_idle_optimizations(struct dc *dc, bool allow)
 {
        if (dc->debug.disable_idle_power_optimizations)
@@ -5315,6 +5347,8 @@ bool dc_abm_save_restore(
        struct dc_link *link = stream->sink->link;
        struct dc_link *edp_links[MAX_NUM_EDP];
 
+       if (link->replay_settings.replay_feature_enabled)
+               return false;
 
        /*find primary pipe associated with stream*/
        for (i = 0; i < MAX_PIPES; i++) {
index f365773d5714857bdcc6fef350dd3f706572c091..c6c35037bdb8b75d538b8d6f1af08556bd4e2236 100644 (file)
@@ -467,6 +467,13 @@ bool dc_link_setup_psr(struct dc_link *link,
        return link->dc->link_srv->edp_setup_psr(link, stream, psr_config, psr_context);
 }
 
+bool dc_link_set_replay_allow_active(struct dc_link *link, const bool *allow_active,
+               bool wait, bool force_static, const unsigned int *power_opts)
+{
+       return link->dc->link_srv->edp_set_replay_allow_active(link, allow_active, wait,
+                       force_static, power_opts);
+}
+
 bool dc_link_get_replay_state(const struct dc_link *link, uint64_t *state)
 {
        return link->dc->link_srv->edp_get_replay_state(link, state);
index 565de7428b6ca183ca00f596f71bc34f0d3beb9b..f30a341bc09014b156dbe4463b41f84b0f16e083 100644 (file)
@@ -463,6 +463,12 @@ enum dml_hostvm_override_opts {
        DML_HOSTVM_OVERRIDE_TRUE = 0x2,
 };
 
+enum dc_replay_power_opts {
+       replay_power_opt_invalid                = 0x0,
+       replay_power_opt_smu_opt_static_screen  = 0x1,
+       replay_power_opt_z10_static_screen      = 0x10,
+};
+
 enum dcc_option {
        DCC_ENABLE = 0,
        DCC_DISABLE = 1,
@@ -2077,6 +2083,20 @@ bool dc_link_setup_psr(struct dc_link *dc_link,
                const struct dc_stream_state *stream, struct psr_config *psr_config,
                struct psr_context *psr_context);
 
+/*
+ * Communicate with DMUB to allow or disallow Panel Replay on the specified link:
+ *
+ * @link: pointer to the dc_link struct instance
+ * @enable: enable(active) or disable(inactive) replay
+ * @wait: state transition need to wait the active set completed.
+ * @force_static: force disable(inactive) the replay
+ * @power_opts: set power optimazation parameters to DMUB.
+ *
+ * return: allow Replay active will return true, else will return false.
+ */
+bool dc_link_set_replay_allow_active(struct dc_link *dc_link, const bool *enable,
+               bool wait, bool force_static, const unsigned int *power_opts);
+
 bool dc_link_get_replay_state(const struct dc_link *dc_link, uint64_t *state);
 
 /* On eDP links this function call will stall until T12 has elapsed.
@@ -2321,6 +2341,9 @@ void dc_hardware_release(struct dc *dc);
 void dc_mclk_switch_using_fw_based_vblank_stretch_shut_down(struct dc *dc);
 
 bool dc_set_psr_allow_active(struct dc *dc, bool enable);
+
+bool dc_set_replay_allow_active(struct dc *dc, bool active);
+
 void dc_z10_restore(const struct dc *dc);
 void dc_z10_save_init(struct dc *dc);
 
index 28149e53c2a68fb2b956c9415cc258b0ca63d826..38e4797e9476ca8de7ba6ad92c6906db5f9823c1 100644 (file)
@@ -258,13 +258,97 @@ static void dmub_replay_residency(struct dmub_replay *dmub, uint8_t panel_inst,
                *residency = 0;
 }
 
+/**
+ * Set REPLAY power optimization flags and coasting vtotal.
+ */
+static void dmub_replay_set_power_opt_and_coasting_vtotal(struct dmub_replay *dmub,
+               unsigned int power_opt, uint8_t panel_inst, uint16_t coasting_vtotal)
+{
+       union dmub_rb_cmd cmd;
+       struct dc_context *dc = dmub->ctx;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.replay_set_power_opt_and_coasting_vtotal.header.type = DMUB_CMD__REPLAY;
+       cmd.replay_set_power_opt_and_coasting_vtotal.header.sub_type =
+               DMUB_CMD__REPLAY_SET_POWER_OPT_AND_COASTING_VTOTAL;
+       cmd.replay_set_power_opt_and_coasting_vtotal.header.payload_bytes =
+               sizeof(struct dmub_rb_cmd_replay_set_power_opt_and_coasting_vtotal);
+       cmd.replay_set_power_opt_and_coasting_vtotal.replay_set_power_opt_data.power_opt = power_opt;
+       cmd.replay_set_power_opt_and_coasting_vtotal.replay_set_power_opt_data.panel_inst = panel_inst;
+       cmd.replay_set_power_opt_and_coasting_vtotal.replay_set_coasting_vtotal_data.coasting_vtotal = coasting_vtotal;
+
+       dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+}
+
+/**
+ * send Replay general cmd to DMUB.
+ */
+static void dmub_replay_send_cmd(struct dmub_replay *dmub,
+               enum replay_FW_Message_type msg, union dmub_replay_cmd_set *cmd_element)
+{
+       union dmub_rb_cmd cmd;
+       struct dc_context *ctx = NULL;
+
+       if (dmub == NULL || cmd_element == NULL)
+               return;
+
+       ctx = dmub->ctx;
+       if (ctx != NULL) {
+
+               if (msg != Replay_Msg_Not_Support) {
+                       memset(&cmd, 0, sizeof(cmd));
+                       //Header
+                       cmd.replay_set_timing_sync.header.type = DMUB_CMD__REPLAY;
+               } else
+                       return;
+       } else
+               return;
+
+       switch (msg) {
+       case Replay_Set_Timing_Sync_Supported:
+               //Header
+               cmd.replay_set_timing_sync.header.sub_type =
+                       DMUB_CMD__REPLAY_SET_TIMING_SYNC_SUPPORTED;
+               cmd.replay_set_timing_sync.header.payload_bytes =
+                       sizeof(struct dmub_rb_cmd_replay_set_timing_sync);
+               //Cmd Body
+               cmd.replay_set_timing_sync.replay_set_timing_sync_data.panel_inst =
+                                               cmd_element->sync_data.panel_inst;
+               cmd.replay_set_timing_sync.replay_set_timing_sync_data.timing_sync_supported =
+                                               cmd_element->sync_data.timing_sync_supported;
+               break;
+       case Replay_Set_Residency_Frameupdate_Timer:
+               //Header
+               cmd.replay_set_frameupdate_timer.header.sub_type =
+                       DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER;
+               cmd.replay_set_frameupdate_timer.header.payload_bytes =
+                       sizeof(struct dmub_rb_cmd_replay_set_frameupdate_timer);
+               //Cmd Body
+               cmd.replay_set_frameupdate_timer.data.panel_inst =
+                                               cmd_element->panel_inst;
+               cmd.replay_set_frameupdate_timer.data.enable =
+                                               cmd_element->timer_data.enable;
+               cmd.replay_set_frameupdate_timer.data.frameupdate_count =
+                                               cmd_element->timer_data.frameupdate_count;
+               break;
+       case Replay_Msg_Not_Support:
+       default:
+               return;
+               break;
+       }
+
+       dc_wake_and_execute_dmub_cmd(ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+}
+
 static const struct dmub_replay_funcs replay_funcs = {
-       .replay_copy_settings           = dmub_replay_copy_settings,
-       .replay_enable                  = dmub_replay_enable,
-       .replay_get_state               = dmub_replay_get_state,
-       .replay_set_power_opt           = dmub_replay_set_power_opt,
-       .replay_set_coasting_vtotal     = dmub_replay_set_coasting_vtotal,
-       .replay_residency               = dmub_replay_residency,
+       .replay_copy_settings                           = dmub_replay_copy_settings,
+       .replay_enable                                  = dmub_replay_enable,
+       .replay_get_state                               = dmub_replay_get_state,
+       .replay_set_power_opt                           = dmub_replay_set_power_opt,
+       .replay_set_coasting_vtotal                     = dmub_replay_set_coasting_vtotal,
+       .replay_residency                               = dmub_replay_residency,
+       .replay_set_power_opt_and_coasting_vtotal       = dmub_replay_set_power_opt_and_coasting_vtotal,
+       .replay_send_cmd                                = dmub_replay_send_cmd,
 };
 
 /*
index b3ee90a0b8b3d28e3115ff4497a20098d9369670..3613aff994d725362dabd5e5cbb75cfc576d1a52 100644 (file)
@@ -51,6 +51,8 @@ struct dmub_replay_funcs {
                uint8_t panel_inst);
        void (*replay_residency)(struct dmub_replay *dmub,
                uint8_t panel_inst, uint32_t *residency, const bool is_start, const bool is_alpm);
+       void (*replay_set_power_opt_and_coasting_vtotal)(struct dmub_replay *dmub,
+               unsigned int power_opt, uint8_t panel_inst, uint16_t coasting_vtotal);
 };
 
 struct dmub_replay *dmub_replay_create(struct dc_context *ctx);
index 7439865d1b50c467fe6af1f0148f31d9cb423a61..26fe81f213da55d39aa7edbb387328192d42685b 100644 (file)
@@ -289,6 +289,8 @@ struct link_service {
        bool (*edp_replay_residency)(const struct dc_link *link,
                        unsigned int *residency, const bool is_start,
                        const bool is_alpm);
+       bool (*edp_set_replay_power_opt_and_coasting_vtotal)(struct dc_link *link,
+                       const unsigned int *power_opts, uint16_t coasting_vtotal);
 
        bool (*edp_wait_for_t12)(struct dc_link *link);
        bool (*edp_is_ilr_optimization_required)(struct dc_link *link,
index 5464d8d26bd371e7df97d0599275dbb705fb5fc9..37d3027c32dcb1007dbb90e209f7f459be81617e 100644 (file)
@@ -216,6 +216,7 @@ static void construct_link_service_edp_panel_control(struct link_service *link_s
        link_srv->edp_send_replay_cmd = edp_send_replay_cmd;
        link_srv->edp_set_coasting_vtotal = edp_set_coasting_vtotal;
        link_srv->edp_replay_residency = edp_replay_residency;
+       link_srv->edp_set_replay_power_opt_and_coasting_vtotal = edp_set_replay_power_opt_and_coasting_vtotal;
 
        link_srv->edp_wait_for_t12 = edp_wait_for_t12;
        link_srv->edp_is_ilr_optimization_required =
index e8de68e62403dc02e75af3c311acd366bdd3c3d1..7f1196528218692c98f1f15375f153dfe56fe514 100644 (file)
@@ -1068,6 +1068,33 @@ bool edp_replay_residency(const struct dc_link *link,
        return true;
 }
 
+bool edp_set_replay_power_opt_and_coasting_vtotal(struct dc_link *link,
+       const unsigned int *power_opts, uint16_t coasting_vtotal)
+{
+       struct dc  *dc = link->ctx->dc;
+       struct dmub_replay *replay = dc->res_pool->replay;
+       unsigned int panel_inst;
+
+       if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
+               return false;
+
+       /* Only both power and coasting vtotal changed, this func could return true */
+       if (power_opts && link->replay_settings.replay_power_opt_active != *power_opts &&
+               coasting_vtotal && link->replay_settings.coasting_vtotal != coasting_vtotal) {
+               if (link->replay_settings.replay_feature_enabled &&
+                       replay->funcs->replay_set_power_opt_and_coasting_vtotal) {
+                       replay->funcs->replay_set_power_opt_and_coasting_vtotal(replay,
+                               *power_opts, panel_inst, coasting_vtotal);
+                       link->replay_settings.replay_power_opt_active = *power_opts;
+                       link->replay_settings.coasting_vtotal = coasting_vtotal;
+               } else
+                       return false;
+       } else
+               return false;
+
+       return true;
+}
+
 static struct abm *get_abm_from_stream_res(const struct dc_link *link)
 {
        int i;
index b7493ff4fceefe049ff79499a47bc8caeb527c17..34e521af7bb482260539bcf66821741531ab17af 100644 (file)
@@ -63,6 +63,8 @@ bool edp_set_coasting_vtotal(struct dc_link *link, uint16_t coasting_vtotal);
 bool edp_replay_residency(const struct dc_link *link,
        unsigned int *residency, const bool is_start, const bool is_alpm);
 bool edp_get_replay_state(const struct dc_link *link, uint64_t *state);
+bool edp_set_replay_power_opt_and_coasting_vtotal(struct dc_link *link,
+       const unsigned int *power_opts, uint16_t coasting_vtotal);
 bool edp_wait_for_t12(struct dc_link *link);
 bool edp_is_ilr_optimization_required(struct dc_link *link,
        struct dc_crtc_timing *crtc_timing);
index 39594e8ffb5ee70946f9b77188ea83c3707828d7..761ec989187568730fdd8cd51cd1802fa657be9c 100644 (file)
@@ -96,6 +96,7 @@
 #include "reg_helper.h"
 #include "dce/dmub_abm.h"
 #include "dce/dmub_psr.h"
+#include "dce/dmub_replay.h"
 #include "dce/dce_aux.h"
 #include "dce/dce_i2c.h"
 #include "dml/dcn31/display_mode_vba_31.h" /*temp*/
@@ -788,6 +789,7 @@ static const struct dc_panel_config panel_config_defaults = {
        .psr = {
                .disable_psr = false,
                .disallow_psrsu = false,
+               .disallow_replay = false,
        },
        .ilr = {
                .optimize_edp_link_rate = true,
@@ -1546,6 +1548,9 @@ static void dcn35_resource_destruct(struct dcn35_resource_pool *pool)
        if (pool->base.psr != NULL)
                dmub_psr_destroy(&pool->base.psr);
 
+       if (pool->base.replay != NULL)
+               dmub_replay_destroy(&pool->base.replay);
+
        if (pool->base.pg_cntl != NULL)
                dcn_pg_cntl_destroy(&pool->base.pg_cntl);
 
@@ -2030,6 +2035,14 @@ static bool dcn35_resource_construct(
                goto create_fail;
        }
 
+       /* Replay */
+       pool->base.replay = dmub_replay_create(ctx);
+       if (pool->base.replay == NULL) {
+               dm_error("DC: failed to create replay obj!\n");
+               BREAK_TO_DEBUGGER();
+               goto create_fail;
+       }
+
        /* ABM */
        for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) {
                pool->base.multiple_abms[i] = dmub_abm_create(ctx,
index 1675314a3ff20856519666689fb56d36a27c60b8..34b848c981e06b168206594e67b682a727d18e50 100644 (file)
@@ -973,6 +973,34 @@ bool psr_su_set_dsc_slice_height(struct dc *dc, struct dc_link *link,
        return true;
 }
 
+void set_replay_coasting_vtotal(struct dc_link *link,
+       enum replay_coasting_vtotal_type type,
+       uint16_t vtotal)
+{
+       link->replay_settings.coasting_vtotal_table[type] = vtotal;
+}
+
+void calculate_replay_link_off_frame_count(struct dc_link *link,
+       uint16_t vtotal, uint16_t htotal)
+{
+       uint8_t max_link_off_frame_count = 0;
+       uint16_t max_deviation_line = 0,  pixel_deviation_per_line = 0;
+
+       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)
+               max_link_off_frame_count = htotal * max_deviation_line / (pixel_deviation_per_line * vtotal);
+       else
+               ASSERT(0);
+
+       link->replay_settings.link_off_frame_count_level =
+               max_link_off_frame_count >= PR_LINK_OFF_FRAME_COUNT_BEST ? PR_LINK_OFF_FRAME_COUNT_BEST :
+               max_link_off_frame_count >= PR_LINK_OFF_FRAME_COUNT_GOOD ? PR_LINK_OFF_FRAME_COUNT_GOOD :
+               PR_LINK_OFF_FRAME_COUNT_FAIL;
+
+}
+
 bool fill_custom_backlight_caps(unsigned int config_no, struct dm_acpi_atif_backlight_caps *caps)
 {
        unsigned int data_points_size;
index d9e0d67d67f703b23f0b124779082e05a53b43db..c17bbc6fb38cafb518777b16c96a99b2116c36eb 100644 (file)
@@ -54,6 +54,11 @@ bool dmub_init_abm_config(struct resource_pool *res_pool,
                unsigned int inst);
 
 void init_replay_config(struct dc_link *link, struct replay_config *pr_config);
+void set_replay_coasting_vtotal(struct dc_link *link,
+       enum replay_coasting_vtotal_type type,
+       uint16_t vtotal);
+void calculate_replay_link_off_frame_count(struct dc_link *link,
+       uint16_t vtotal, uint16_t htotal);
 
 bool is_psr_su_specific_panel(struct dc_link *link);
 void mod_power_calc_psr_configs(struct psr_config *psr_config,
index 5cad456f2e10db2e0a1546e9194f86d4f3b07999..1dc5dd9b7bf70b10641a76e4c731e3e735aeaeef 100644 (file)
@@ -257,6 +257,7 @@ enum DC_DEBUG_MASK {
        DC_ENABLE_DPIA_TRACE = 0x80,
        DC_ENABLE_DML2 = 0x100,
        DC_DISABLE_PSR_SU = 0x200,
+       DC_DISABLE_REPLAY = 0x400,
 };
 
 enum amd_dpm_forced_level;