From: Peichen Huang <[email protected]> [WHY] Panel Replay is not an eDP-specific function.
[HOW] Create new Panel Replay source files and move the Panel Replay functions from the eDP files to the new files. Additionally, create a new link_service construct function to assign the related function pointers. Reviewed-by: Robin Chen <[email protected]> Signed-off-by: Peichen Huang <[email protected]> Signed-off-by: Matthew Stewart <[email protected]> --- .../amd/display/amdgpu_dm/amdgpu_dm_replay.c | 2 +- .../drm/amd/display/dc/core/dc_link_exports.c | 9 +- .../gpu/drm/amd/display/dc/inc/link_service.h | 10 +- drivers/gpu/drm/amd/display/dc/link/Makefile | 2 +- .../drm/amd/display/dc/link/link_factory.c | 18 +- .../dc/link/protocols/link_dp_irq_handler.c | 1 + .../dc/link/protocols/link_dp_panel_replay.c | 308 ++++++++++++++++++ .../dc/link/protocols/link_dp_panel_replay.h | 38 +++ .../link/protocols/link_edp_panel_control.c | 271 +-------------- .../link/protocols/link_edp_panel_control.h | 8 +- 10 files changed, 373 insertions(+), 294 deletions(-) create mode 100644 drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c create mode 100644 drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.h diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c index da94e3544b65..fb619a3336b7 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c @@ -161,7 +161,7 @@ bool amdgpu_dm_replay_enable(struct dc_stream_state *stream, bool wait) link = stream->link; if (link) { - link->dc->link_srv->edp_setup_replay(link, stream); + link->dc->link_srv->dp_setup_replay(link, stream); link->dc->link_srv->edp_set_coasting_vtotal(link, stream->timing.v_total, 0); DRM_DEBUG_DRIVER("Enabling replay...\n"); link->dc->link_srv->edp_set_replay_allow_active(link, &replay_active, wait, false, NULL); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c index a8d7228907c2..7bb4504889be 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c @@ -493,24 +493,24 @@ bool dc_link_get_replay_state(const struct dc_link *link, uint64_t *state) bool dc_link_set_pr_enable(struct dc_link *link, bool enable) { - return link->dc->link_srv->edp_pr_enable(link, enable); + return link->dc->link_srv->dp_pr_enable(link, enable); } bool dc_link_update_pr_state(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data) { - return link->dc->link_srv->edp_pr_update_state(link, update_state_data); + return link->dc->link_srv->dp_pr_update_state(link, update_state_data); } bool dc_link_set_pr_general_cmd(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data) { - return link->dc->link_srv->edp_pr_set_general_cmd(link, general_cmd_data); + return link->dc->link_srv->dp_pr_set_general_cmd(link, general_cmd_data); } bool dc_link_get_pr_state(const struct dc_link *link, uint64_t *state) { - return link->dc->link_srv->edp_pr_get_state(link, state); + return link->dc->link_srv->dp_pr_get_state(link, state); } bool dc_link_wait_for_t12(struct dc_link *link) @@ -549,4 +549,3 @@ void dc_link_get_alpm_support(struct dc_link *link, { link->dc->link_srv->edp_get_alpm_support(link, auxless_support, auxwake_support); } - diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_service.h b/drivers/gpu/drm/amd/display/dc/inc/link_service.h index 4b092a9ee4c6..5885b4abdf38 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link_service.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link_service.h @@ -283,7 +283,7 @@ struct link_service { bool (*edp_set_replay_allow_active)(struct dc_link *dc_link, const bool *enable, bool wait, bool force_static, const unsigned int *power_opts); - bool (*edp_setup_replay)(struct dc_link *link, + bool (*dp_setup_replay)(struct dc_link *link, const struct dc_stream_state *stream); bool (*edp_send_replay_cmd)(struct dc_link *link, enum replay_FW_Message_type msg, @@ -304,10 +304,10 @@ struct link_service { bool (*edp_receiver_ready_T9)(struct dc_link *link); bool (*edp_receiver_ready_T7)(struct dc_link *link); bool (*edp_power_alpm_dpcd_enable)(struct dc_link *link, bool enable); - bool (*edp_pr_enable)(struct dc_link *link, bool enable); - bool (*edp_pr_update_state)(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data); - bool (*edp_pr_set_general_cmd)(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data); - bool (*edp_pr_get_state)(const struct dc_link *link, uint64_t *state); + bool (*dp_pr_enable)(struct dc_link *link, bool enable); + bool (*dp_pr_update_state)(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data); + bool (*dp_pr_set_general_cmd)(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data); + bool (*dp_pr_get_state)(const struct dc_link *link, uint64_t *state); void (*edp_set_panel_power)(struct dc_link *link, bool powerOn); diff --git a/drivers/gpu/drm/amd/display/dc/link/Makefile b/drivers/gpu/drm/amd/display/dc/link/Makefile index 84c7af5fa589..84dace27daf7 100644 --- a/drivers/gpu/drm/amd/display/dc/link/Makefile +++ b/drivers/gpu/drm/amd/display/dc/link/Makefile @@ -56,7 +56,7 @@ LINK_PROTOCOLS = link_hpd.o link_ddc.o link_dpcd.o link_dp_dpia.o \ link_dp_training.o link_dp_training_8b_10b.o link_dp_training_128b_132b.o \ link_dp_training_dpia.o link_dp_training_auxless.o \ link_dp_training_fixed_vs_pe_retimer.o link_dp_phy.o link_dp_capability.o \ -link_edp_panel_control.o link_dp_irq_handler.o link_dp_dpia_bw.o +link_edp_panel_control.o link_dp_panel_replay.o link_dp_irq_handler.o link_dp_dpia_bw.o AMD_DAL_LINK_PROTOCOLS = $(addprefix $(AMDDALPATH)/dc/link/protocols/, \ $(LINK_PROTOCOLS)) diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c index 923517715651..e185f2caad0c 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c @@ -41,6 +41,7 @@ #include "protocols/link_dp_phy.h" #include "protocols/link_dp_training.h" #include "protocols/link_edp_panel_control.h" +#include "protocols/link_dp_panel_replay.h" #include "protocols/link_hpd.h" #include "gpio_service_interface.h" #include "atomfirmware.h" @@ -214,7 +215,6 @@ static void construct_link_service_edp_panel_control(struct link_service *link_s link_srv->edp_get_replay_state = edp_get_replay_state; link_srv->edp_set_replay_allow_active = edp_set_replay_allow_active; - link_srv->edp_setup_replay = edp_setup_replay; 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; @@ -228,13 +228,20 @@ static void construct_link_service_edp_panel_control(struct link_service *link_s link_srv->edp_receiver_ready_T9 = edp_receiver_ready_T9; link_srv->edp_receiver_ready_T7 = edp_receiver_ready_T7; link_srv->edp_power_alpm_dpcd_enable = edp_power_alpm_dpcd_enable; - link_srv->edp_pr_enable = edp_pr_enable; - link_srv->edp_pr_update_state = edp_pr_update_state; - link_srv->edp_pr_set_general_cmd = edp_pr_set_general_cmd; - link_srv->edp_pr_get_state = edp_pr_get_state; link_srv->edp_set_panel_power = edp_set_panel_power; } +/* link dp panel replay implements DP panel replay functionality. + */ +static void construct_link_service_dp_panel_replay(struct link_service *link_srv) +{ + link_srv->dp_setup_replay = dp_setup_replay; + link_srv->dp_pr_enable = dp_pr_enable; + link_srv->dp_pr_update_state = dp_pr_update_state; + link_srv->dp_pr_set_general_cmd = dp_pr_set_general_cmd; + link_srv->dp_pr_get_state = dp_pr_get_state; +} + /* link dp cts implements dp compliance test automation protocols and manual * testing interfaces for debugging and certification purpose. */ @@ -287,6 +294,7 @@ static void construct_link_service(struct link_service *link_srv) construct_link_service_dp_phy_or_dpia(link_srv); construct_link_service_dp_irq_handler(link_srv); construct_link_service_edp_panel_control(link_srv); + construct_link_service_dp_panel_replay(link_srv); construct_link_service_dp_cts(link_srv); construct_link_service_dp_trace(link_srv); } diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c index 4b01ab0a5a7f..47abd3ec69b3 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c @@ -38,6 +38,7 @@ #include "link/link_dpms.h" #include "dm_helpers.h" #include "link_dp_dpia_bw.h" +#include "link_dp_panel_replay.h" #define DC_LOGGER \ link->ctx->logger diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c new file mode 100644 index 000000000000..3168c42d662c --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c @@ -0,0 +1,308 @@ +/* + * Copyright 2025 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "link_dp_panel_replay.h" +#include "link_edp_panel_control.h" +#include "link_dpcd.h" +#include "dm_helpers.h" +#include "dc/dc_dmub_srv.h" +#include "dce/dmub_replay.h" + +#define DC_LOGGER \ + link->ctx->logger + +#define DP_SINK_PR_ENABLE_AND_CONFIGURATION 0x37B + +static bool dp_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 = dp_pr_copy_settings(link, &replay_context); + + 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; +} + +bool dp_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 dp_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; +} + +bool dp_pr_enable(struct dc_link *link, bool enable) +{ + struct dc *dc = link->ctx->dc; + unsigned int panel_inst = 0; + union dmub_rb_cmd cmd; + + if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + return false; + + if (link->replay_settings.replay_allow_active != enable) { + //for sending PR enable commands to DMUB + memset(&cmd, 0, sizeof(cmd)); + + cmd.pr_enable.header.type = DMUB_CMD__PR; + cmd.pr_enable.header.sub_type = DMUB_CMD__PR_ENABLE; + cmd.pr_enable.header.payload_bytes = sizeof(struct dmub_cmd_pr_enable_data); + cmd.pr_enable.data.panel_inst = panel_inst; + cmd.pr_enable.data.enable = enable ? 1 : 0; + + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + + link->replay_settings.replay_allow_active = enable; + } + return true; +} + +bool dp_pr_copy_settings(struct dc_link *link, struct replay_context *replay_context) +{ + struct dc *dc = link->ctx->dc; + unsigned int panel_inst = 0; + union dmub_rb_cmd cmd; + struct pipe_ctx *pipe_ctx = NULL; + + if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + return false; + + for (unsigned int i = 0; i < MAX_PIPES; i++) { + if (dc->current_state->res_ctx.pipe_ctx[i].stream && + dc->current_state->res_ctx.pipe_ctx[i].stream->link && + dc->current_state->res_ctx.pipe_ctx[i].stream->link == link && + dc->current_state->res_ctx.pipe_ctx[i].stream->link->connector_signal == SIGNAL_TYPE_EDP) { + pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + //TODO: refactor for multi edp support + break; + } + } + + if (!pipe_ctx) + return false; + + memset(&cmd, 0, sizeof(cmd)); + cmd.pr_copy_settings.header.type = DMUB_CMD__PR; + cmd.pr_copy_settings.header.sub_type = DMUB_CMD__PR_COPY_SETTINGS; + cmd.pr_copy_settings.header.payload_bytes = sizeof(struct dmub_cmd_pr_copy_settings_data); + cmd.pr_copy_settings.data.panel_inst = panel_inst; + // HW inst + cmd.pr_copy_settings.data.aux_inst = replay_context->aux_inst; + cmd.pr_copy_settings.data.digbe_inst = replay_context->digbe_inst; + cmd.pr_copy_settings.data.digfe_inst = replay_context->digfe_inst; + if (pipe_ctx->plane_res.dpp) + cmd.pr_copy_settings.data.dpp_inst = pipe_ctx->plane_res.dpp->inst; + else + cmd.pr_copy_settings.data.dpp_inst = 0; + if (pipe_ctx->stream_res.tg) + cmd.pr_copy_settings.data.otg_inst = pipe_ctx->stream_res.tg->inst; + else + cmd.pr_copy_settings.data.otg_inst = 0; + + cmd.pr_copy_settings.data.dpphy_inst = link->link_enc->transmitter; + + cmd.pr_copy_settings.data.line_time_in_ns = replay_context->line_time_in_ns; + cmd.pr_copy_settings.data.flags.bitfields.fec_enable_status = (link->fec_state == dc_link_fec_enabled); + cmd.pr_copy_settings.data.flags.bitfields.dsc_enable_status = (pipe_ctx->stream->timing.flags.DSC == 1); + cmd.pr_copy_settings.data.debug.u32All = link->replay_settings.config.debug_flags; + + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + return true; +} + +bool dp_pr_update_state(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data) +{ + struct dc *dc = link->ctx->dc; + unsigned int panel_inst = 0; + union dmub_rb_cmd cmd; + + if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + return false; + + memset(&cmd, 0, sizeof(cmd)); + cmd.pr_update_state.header.type = DMUB_CMD__PR; + cmd.pr_update_state.header.sub_type = DMUB_CMD__PR_UPDATE_STATE; + cmd.pr_update_state.header.payload_bytes = sizeof(struct dmub_cmd_pr_update_state_data); + cmd.pr_update_state.data.panel_inst = panel_inst; + + memcpy(&cmd.pr_update_state.data, update_state_data, sizeof(struct dmub_cmd_pr_update_state_data)); + + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + return true; +} + +bool dp_pr_set_general_cmd(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data) +{ + struct dc *dc = link->ctx->dc; + unsigned int panel_inst = 0; + union dmub_rb_cmd cmd; + + if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + return false; + + memset(&cmd, 0, sizeof(cmd)); + cmd.pr_general_cmd.header.type = DMUB_CMD__PR; + cmd.pr_general_cmd.header.sub_type = DMUB_CMD__PR_GENERAL_CMD; + cmd.pr_general_cmd.header.payload_bytes = sizeof(struct dmub_cmd_pr_general_cmd_data); + cmd.pr_general_cmd.data.panel_inst = panel_inst; + + memcpy(&cmd.pr_general_cmd.data, general_cmd_data, sizeof(struct dmub_cmd_pr_general_cmd_data)); + + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + return true; +} + +bool dp_pr_get_state(const struct dc_link *link, uint64_t *state) +{ + const struct dc *dc = link->ctx->dc; + unsigned int panel_inst = 0; + uint32_t retry_count = 0; + uint32_t replay_state = 0; + + if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + return false; + + do { + // Send gpint command and wait for ack + if (!dc_wake_and_execute_gpint(dc->ctx, DMUB_GPINT__GET_REPLAY_STATE, panel_inst, + &replay_state, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) { + // Return invalid state when GPINT times out + replay_state = PR_STATE_INVALID; + } + /* Copy 32-bit result into 64-bit output */ + *state = replay_state; + } while (++retry_count <= 1000 && *state == PR_STATE_INVALID); + + // Assert if max retry hit + if (retry_count >= 1000 && *state == PR_STATE_INVALID) { + ASSERT(0); + /* To-do: Add retry fail log */ + } + + return true; +} diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.h new file mode 100644 index 000000000000..b936092edb85 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.h @@ -0,0 +1,38 @@ +/* + * Copyright 2025 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ +#ifndef __DC_LINK_DP_PANEL_REPLAY_H__ +#define __DC_LINK_DP_PANEL_REPLAY_H__ + +#include "link_service.h" + +bool dp_setup_replay(struct dc_link *link, + const struct dc_stream_state *stream); +bool dp_pr_enable(struct dc_link *link, bool enable); +bool dp_pr_copy_settings(struct dc_link *link, struct replay_context *replay_context); +bool dp_pr_update_state(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data); +bool dp_pr_set_general_cmd(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data); +bool dp_pr_get_state(const struct dc_link *link, uint64_t *state); + +#endif /* __DC_LINK_DP_PANEL_REPLAY_H__ */ \ No newline at end of file diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c index d6e91da72ef8..ab047ff556a1 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c @@ -1003,116 +1003,8 @@ bool edp_get_replay_state(const struct dc_link *link, uint64_t *state) return true; } -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 = edp_pr_copy_settings(link, &replay_context); - - 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) +bool edp_setup_freesync_replay(struct dc_link *link, const struct dc_stream_state *stream) { /* To-do: Setup Replay */ struct dc *dc; @@ -1208,17 +1100,6 @@ static bool edp_setup_freesync_replay(struct dc_link *link, const struct dc_stre 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 @@ -1323,156 +1204,6 @@ bool edp_set_replay_power_opt_and_coasting_vtotal(struct dc_link *link, return true; } -bool edp_pr_enable(struct dc_link *link, bool enable) -{ - struct dc *dc = link->ctx->dc; - unsigned int panel_inst = 0; - union dmub_rb_cmd cmd; - - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) - return false; - - if (link->replay_settings.replay_allow_active != enable) { - //for sending PR enable commands to DMUB - memset(&cmd, 0, sizeof(cmd)); - - cmd.pr_enable.header.type = DMUB_CMD__PR; - cmd.pr_enable.header.sub_type = DMUB_CMD__PR_ENABLE; - cmd.pr_enable.header.payload_bytes = sizeof(struct dmub_cmd_pr_enable_data); - cmd.pr_enable.data.panel_inst = panel_inst; - cmd.pr_enable.data.enable = enable ? 1 : 0; - - dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); - - link->replay_settings.replay_allow_active = enable; - } - return true; -} - -bool edp_pr_copy_settings(struct dc_link *link, struct replay_context *replay_context) -{ - struct dc *dc = link->ctx->dc; - unsigned int panel_inst = 0; - union dmub_rb_cmd cmd; - struct pipe_ctx *pipe_ctx = NULL; - - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) - return false; - - for (unsigned int i = 0; i < MAX_PIPES; i++) { - if (dc->current_state->res_ctx.pipe_ctx[i].stream && - dc->current_state->res_ctx.pipe_ctx[i].stream->link && - dc->current_state->res_ctx.pipe_ctx[i].stream->link == link && - dc->current_state->res_ctx.pipe_ctx[i].stream->link->connector_signal == SIGNAL_TYPE_EDP) { - pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; - //TODO: refactor for multi edp support - break; - } - } - - if (!pipe_ctx) - return false; - - memset(&cmd, 0, sizeof(cmd)); - cmd.pr_copy_settings.header.type = DMUB_CMD__PR; - cmd.pr_copy_settings.header.sub_type = DMUB_CMD__PR_COPY_SETTINGS; - cmd.pr_copy_settings.header.payload_bytes = sizeof(struct dmub_cmd_pr_copy_settings_data); - cmd.pr_copy_settings.data.panel_inst = panel_inst; - // HW inst - cmd.pr_copy_settings.data.aux_inst = replay_context->aux_inst; - cmd.pr_copy_settings.data.digbe_inst = replay_context->digbe_inst; - cmd.pr_copy_settings.data.digfe_inst = replay_context->digfe_inst; - if (pipe_ctx->plane_res.dpp) - cmd.pr_copy_settings.data.dpp_inst = pipe_ctx->plane_res.dpp->inst; - else - cmd.pr_copy_settings.data.dpp_inst = 0; - if (pipe_ctx->stream_res.tg) - cmd.pr_copy_settings.data.otg_inst = pipe_ctx->stream_res.tg->inst; - else - cmd.pr_copy_settings.data.otg_inst = 0; - - cmd.pr_copy_settings.data.dpphy_inst = link->link_enc->transmitter; - - cmd.pr_copy_settings.data.line_time_in_ns = replay_context->line_time_in_ns; - cmd.pr_copy_settings.data.flags.bitfields.fec_enable_status = (link->fec_state == dc_link_fec_enabled); - cmd.pr_copy_settings.data.flags.bitfields.dsc_enable_status = (pipe_ctx->stream->timing.flags.DSC == 1); - cmd.pr_copy_settings.data.debug.u32All = link->replay_settings.config.debug_flags; - - dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); - return true; -} - -bool edp_pr_update_state(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data) -{ - struct dc *dc = link->ctx->dc; - unsigned int panel_inst = 0; - union dmub_rb_cmd cmd; - - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) - return false; - - memset(&cmd, 0, sizeof(cmd)); - cmd.pr_update_state.header.type = DMUB_CMD__PR; - cmd.pr_update_state.header.sub_type = DMUB_CMD__PR_UPDATE_STATE; - cmd.pr_update_state.header.payload_bytes = sizeof(struct dmub_cmd_pr_update_state_data); - cmd.pr_update_state.data.panel_inst = panel_inst; - - memcpy(&cmd.pr_update_state.data, update_state_data, sizeof(struct dmub_cmd_pr_update_state_data)); - - dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); - return true; -} - -bool edp_pr_set_general_cmd(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data) -{ - struct dc *dc = link->ctx->dc; - unsigned int panel_inst = 0; - union dmub_rb_cmd cmd; - - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) - return false; - - memset(&cmd, 0, sizeof(cmd)); - cmd.pr_general_cmd.header.type = DMUB_CMD__PR; - cmd.pr_general_cmd.header.sub_type = DMUB_CMD__PR_GENERAL_CMD; - cmd.pr_general_cmd.header.payload_bytes = sizeof(struct dmub_cmd_pr_general_cmd_data); - cmd.pr_general_cmd.data.panel_inst = panel_inst; - - memcpy(&cmd.pr_general_cmd.data, general_cmd_data, sizeof(struct dmub_cmd_pr_general_cmd_data)); - - dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); - return true; -} - -bool edp_pr_get_state(const struct dc_link *link, uint64_t *state) -{ - const struct dc *dc = link->ctx->dc; - unsigned int panel_inst = 0; - uint32_t retry_count = 0; - uint32_t replay_state = 0; - - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) - return false; - - do { - // Send gpint command and wait for ack - if (!dc_wake_and_execute_gpint(dc->ctx, DMUB_GPINT__GET_REPLAY_STATE, panel_inst, - &replay_state, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) { - // Return invalid state when GPINT times out - replay_state = PR_STATE_INVALID; - } - /* Copy 32-bit result into 64-bit output */ - *state = replay_state; - } while (++retry_count <= 1000 && *state == PR_STATE_INVALID); - - // Assert if max retry hit - if (retry_count >= 1000 && *state == PR_STATE_INVALID) { - ASSERT(0); - /* To-do: Add retry fail log */ - } - - return true; -} static struct abm *get_abm_from_stream_res(const struct dc_link *link) { diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h index fd63b5d0f948..8780bbc4e8c5 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h @@ -54,8 +54,6 @@ bool edp_set_sink_vtotal_in_psr_active(const struct dc_link *link, void edp_get_psr_residency(const struct dc_link *link, uint32_t *residency, enum psr_residency_mode mode); bool edp_set_replay_allow_active(struct dc_link *dc_link, const bool *enable, bool wait, bool force_static, const unsigned int *power_opts); -bool edp_setup_replay(struct dc_link *link, - const struct dc_stream_state *stream); bool edp_send_replay_cmd(struct dc_link *link, enum replay_FW_Message_type msg, union dmub_replay_cmd_set *cmd_data); @@ -75,11 +73,7 @@ void edp_add_delay_for_T9(struct dc_link *link); bool edp_receiver_ready_T9(struct dc_link *link); bool edp_receiver_ready_T7(struct dc_link *link); bool edp_power_alpm_dpcd_enable(struct dc_link *link, bool enable); -bool edp_pr_enable(struct dc_link *link, bool enable); -bool edp_pr_copy_settings(struct dc_link *link, struct replay_context *replay_context); -bool edp_pr_update_state(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data); -bool edp_pr_set_general_cmd(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data); -bool edp_pr_get_state(const struct dc_link *link, uint64_t *state); +bool edp_setup_freesync_replay(struct dc_link *link, const struct dc_stream_state *stream); void edp_set_panel_power(struct dc_link *link, bool powerOn); void edp_set_panel_assr(struct dc_link *link, struct pipe_ctx *pipe_ctx, enum dp_panel_mode *panel_mode, bool enable); -- 2.52.0
