From 74ce00932e7eec6a985c2b650e95fce0f334d772 Mon Sep 17 00:00:00 2001 From: Jack Chang Date: Wed, 3 Sep 2025 15:41:15 +0800 Subject: [PATCH] drm/amd/display: Refactor panel replay set dmub cmd flow [WHY] Add link service interface for setting PR dmub command Reviewed-by: Robin Chen Signed-off-by: Jack Chang Signed-off-by: Leon Huang Signed-off-by: Alex Hung Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/inc/link_service.h | 4 + .../drm/amd/display/dc/link/link_factory.c | 4 + .../link/protocols/link_edp_panel_control.c | 146 +++++++++++++++++- .../link/protocols/link_edp_panel_control.h | 5 + 4 files changed, 157 insertions(+), 2 deletions(-) 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 6f94e48a24d1b..2f805ba19a523 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link_service.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link_service.h @@ -307,6 +307,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); void (*edp_set_panel_power)(struct dc_link *link, bool powerOn); 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 a6e2b0821969b..e9af184dbe5df 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c @@ -229,6 +229,10 @@ 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; } 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 c56e69eb27efe..80ee6efe91e2d 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 @@ -1049,8 +1049,7 @@ static bool edp_setup_panel_replay(struct dc_link *link, const struct dc_stream_ replay_context.line_time_in_ns = lineTimeInNs; - link->replay_settings.replay_feature_enabled = - replay->funcs->replay_copy_settings(replay, link, &replay_context, panel_inst); + 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; @@ -1305,6 +1304,149 @@ 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; + + //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); + 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); + + 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; + + 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, + (uint32_t *)state, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) { + // Return invalid state when GPINT times out + *state = PR_STATE_INVALID; + } + } 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) { int i; 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 dd79c7cd2828d..360129732109c 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 @@ -75,6 +75,11 @@ 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); 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.47.3