]> Gentwo Git Trees - linux/.git/commitdiff
drm/amd/display: Add panel replay enablement option and logic
authorJack Chang <jack.chang@amd.com>
Thu, 21 Aug 2025 05:19:23 +0000 (13:19 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 18 Nov 2025 15:50:06 +0000 (10:50 -0500)
[Why&How]
1.Add flow to enable and configure panel replay enablement and
configuration
2.Add registry key for enable option
3.Add replay version check to be compatible with freesync replay
4.Add AC/DC switch function to notify ac/dc change.
5.Add flow in set event function to check and decide Replay
enable/disable

Reviewed-by: Robin Chen <robin.chen@amd.com>
Signed-off-by: Jack Chang <jack.chang@amd.com>
Signed-off-by: Leon Huang <Leon.Huang1@amd.com>
Signed-off-by: Ivan Lipski <ivan.lipski@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/dc_dp_types.h
drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
drivers/gpu/drm/amd/display/include/dpcd_defs.h
drivers/gpu/drm/amd/display/modules/power/power_helpers.c

index db669ccb1d587fd9f440ae5b071cd2705c2c24f6..17bcff25a26268b2101575909cf2bd4729f6c058 100644 (file)
@@ -1346,6 +1346,31 @@ union dpcd_replay_configuration {
        unsigned char raw;
 };
 
+union panel_replay_enable_and_configuration_1 {
+       struct {
+               unsigned char PANEL_REPLAY_ENABLE                     :1;
+               unsigned char PANEL_REPLAY_CRC_ENABLE                 :1;
+               unsigned char IRQ_HPD_ASSDP_MISSING                   :1;
+               unsigned char IRQ_HPD_VSCSDP_UNCORRECTABLE_ERROR      :1;
+               unsigned char IRQ_HPD_RFB_ERROR                       :1;
+               unsigned char IRQ_HPD_ACTIVE_FRAME_CRC_ERROR          :1;
+               unsigned char PANEL_REPLAY_SELECTIVE_UPDATE_ENABLE    :1;
+               unsigned char PANEL_REPLAY_EARLY_TRANSPORT_ENABLE     :1;
+       } bits;
+       unsigned char raw;
+};
+
+union panel_replay_enable_and_configuration_2 {
+       struct {
+               unsigned char SINK_REFRESH_RATE_UNLOCK_GRANTED        :1;
+               unsigned char RESERVED                                :1;
+               unsigned char SU_Y_GRANULARITY_EXT_VALUE_ENABLED      :1;
+               unsigned char SU_Y_GRANULARITY_EXT_VALUE              :4;
+               unsigned char SU_REGION_SCAN_LINE_CAPTURE_INDICATION  :1;
+       } bits;
+       unsigned char raw;
+};
+
 union dpcd_alpm_configuration {
        struct {
                unsigned char ENABLE                    : 1;
index 9391c75a30e57a8c1aa2b9219972c3c2ae7b2d74..c56e69eb27efec973117e53e421420548a960e1d 100644 (file)
@@ -949,7 +949,7 @@ bool edp_set_replay_allow_active(struct dc_link *link, const bool *allow_active,
        /* Set power optimization flag */
        if (power_opts && link->replay_settings.replay_power_opt_active != *power_opts) {
                if (replay != NULL && link->replay_settings.replay_feature_enabled &&
-                   replay->funcs->replay_set_power_opt) {
+                       replay->funcs->replay_set_power_opt) {
                        replay->funcs->replay_set_power_opt(replay, *power_opts, panel_inst);
                        link->replay_settings.replay_power_opt_active = *power_opts;
                }
@@ -984,7 +984,117 @@ bool edp_get_replay_state(const struct dc_link *link, uint64_t *state)
        return true;
 }
 
-bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream)
+static bool edp_setup_panel_replay(struct dc_link *link, const struct dc_stream_state *stream)
+{
+       /* To-do: Setup Replay */
+       struct dc *dc;
+       struct dmub_replay *replay;
+       int i;
+       unsigned int panel_inst;
+       struct replay_context replay_context = { 0 };
+       unsigned int lineTimeInNs = 0;
+
+       union panel_replay_enable_and_configuration_1 pr_config_1 = { 0 };
+       union panel_replay_enable_and_configuration_2 pr_config_2 = { 0 };
+
+       union dpcd_alpm_configuration alpm_config;
+
+       replay_context.controllerId = CONTROLLER_ID_UNDEFINED;
+
+       if (!link)
+               return false;
+
+       //Clear Panel Replay enable & config
+       dm_helpers_dp_write_dpcd(link->ctx, link,
+               DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1,
+               (uint8_t *)&(pr_config_1.raw), sizeof(uint8_t));
+
+       dm_helpers_dp_write_dpcd(link->ctx, link,
+               DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2,
+               (uint8_t *)&(pr_config_2.raw), sizeof(uint8_t));
+
+       if (!(link->replay_settings.config.replay_supported))
+               return false;
+
+       dc = link->ctx->dc;
+
+       //not sure should keep or not
+       replay = dc->res_pool->replay;
+
+       if (!replay)
+               return false;
+
+       if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
+               return false;
+
+       replay_context.aux_inst = link->ddc->ddc_pin->hw_info.ddc_channel;
+       replay_context.digbe_inst = link->link_enc->transmitter;
+       replay_context.digfe_inst = link->link_enc->preferred_engine;
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               if (dc->current_state->res_ctx.pipe_ctx[i].stream
+                               == stream) {
+                       /* dmcu -1 for all controller id values,
+                        * therefore +1 here
+                        */
+                       replay_context.controllerId =
+                               dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg->inst + 1;
+                       break;
+               }
+       }
+
+       lineTimeInNs =
+               ((stream->timing.h_total * 1000000) /
+                       (stream->timing.pix_clk_100hz / 10)) + 1;
+
+       replay_context.line_time_in_ns = lineTimeInNs;
+
+       link->replay_settings.replay_feature_enabled =
+                       replay->funcs->replay_copy_settings(replay, link, &replay_context, panel_inst);
+
+       if (link->replay_settings.replay_feature_enabled) {
+               pr_config_1.bits.PANEL_REPLAY_ENABLE = 1;
+               pr_config_1.bits.PANEL_REPLAY_CRC_ENABLE = 1;
+               pr_config_1.bits.IRQ_HPD_ASSDP_MISSING = 1;
+               pr_config_1.bits.IRQ_HPD_VSCSDP_UNCORRECTABLE_ERROR = 1;
+               pr_config_1.bits.IRQ_HPD_RFB_ERROR = 1;
+               pr_config_1.bits.IRQ_HPD_ACTIVE_FRAME_CRC_ERROR = 1;
+               pr_config_1.bits.PANEL_REPLAY_SELECTIVE_UPDATE_ENABLE = 1;
+               pr_config_1.bits.PANEL_REPLAY_EARLY_TRANSPORT_ENABLE = 1;
+
+               pr_config_2.bits.SINK_REFRESH_RATE_UNLOCK_GRANTED = 0;
+               pr_config_2.bits.SU_Y_GRANULARITY_EXT_VALUE_ENABLED = 0;
+               pr_config_2.bits.SU_REGION_SCAN_LINE_CAPTURE_INDICATION = 0;
+
+               dm_helpers_dp_write_dpcd(link->ctx, link,
+                       DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1,
+                       (uint8_t *)&(pr_config_1.raw), sizeof(uint8_t));
+
+               dm_helpers_dp_write_dpcd(link->ctx, link,
+                       DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2,
+                       (uint8_t *)&(pr_config_2.raw), sizeof(uint8_t));
+
+               //ALPM Setup
+               memset(&alpm_config, 0, sizeof(alpm_config));
+               alpm_config.bits.ENABLE = link->replay_settings.config.alpm_mode != DC_ALPM_UNSUPPORTED ? 1 : 0;
+
+               if (link->replay_settings.config.alpm_mode == DC_ALPM_AUXLESS) {
+                       alpm_config.bits.ALPM_MODE_SEL = 1;
+                       alpm_config.bits.ACDS_PERIOD_DURATION = 1;
+               }
+
+               dm_helpers_dp_write_dpcd(
+                       link->ctx,
+                       link,
+                       DP_RECEIVER_ALPM_CONFIG,
+                       &alpm_config.raw,
+                       sizeof(alpm_config.raw));
+       }
+
+       return true;
+}
+
+static bool edp_setup_freesync_replay(struct dc_link *link, const struct dc_stream_state *stream)
 {
        /* To-do: Setup Replay */
        struct dc *dc;
@@ -1080,6 +1190,18 @@ bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream
        return true;
 }
 
+bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream)
+{
+       if (!link)
+               return false;
+       if (link->replay_settings.config.replay_version == DC_VESA_PANEL_REPLAY)
+               return edp_setup_panel_replay(link, stream);
+       else if (link->replay_settings.config.replay_version == DC_FREESYNC_REPLAY)
+               return edp_setup_freesync_replay(link, stream);
+       else
+               return false;
+}
+
 /*
  * This is general Interface for Replay to set an 32 bit variable to dmub
  * replay_FW_Message_type: Indicates which instruction or variable pass to DMUB
index de8f3cfed6c84f66970aa30156fc69b26022d3be..07b937b92efc7a31d3b0ca20847e615835abfb27 100644 (file)
 #ifndef DP_SINK_HW_REVISION_START // can remove this once the define gets into linux drm_dp_helper.h
 #define DP_SINK_HW_REVISION_START 0x409
 #endif
+/* Panel Replay*/
+#ifndef DP_PANEL_REPLAY_CAPABILITY_SUPPORT // can remove this once the define gets into linux drm_dp_helper.h
+#define DP_PANEL_REPLAY_CAPABILITY_SUPPORT 0x0b0
+#endif /* DP_PANEL_REPLAY_CAPABILITY_SUPPORT */
+#ifndef DP_PANEL_REPLAY_CAPABILITY // can remove this once the define gets into linux drm_dp_helper.h
+#define DP_PANEL_REPLAY_CAPABILITY 0x0b1
+#endif /* DP_PANEL_REPLAY_CAPABILITY */
+#ifndef DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1  // can remove this once the define gets into linux drm_dp_helper.h
+#define DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1  0x1b0
+#endif /* DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1 */
+#ifndef DP_PANEL_REPLAY_ENABLE // can remove this once the define gets into linux drm_dp_helper.h
+#define DP_PANEL_REPLAY_ENABLE (1 << 0)
+#endif /* DP_PANEL_REPLAY_ENABLE */
+#ifndef DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2 // can remove this once the define gets into linux drm_dp_helper.h
+#define DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2 0x1b1
+#endif /* DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2 */
 
 enum dpcd_revision {
        DPCD_REV_10 = 0x10,
index 88b5b716a0847ad6c01ed6fa7f0b519349c713f7..fd139b219bf9a5799822bb145afd937b74f7f7d9 100644 (file)
@@ -1037,6 +1037,9 @@ void calculate_replay_link_off_frame_count(struct dc_link *link,
        uint8_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;