Skip to content

Commit

Permalink
drm/amd/display: Add Support for reg inbox0 for host->DMUB CMDs
Browse files Browse the repository at this point in the history
[WHY]
DCN4+ supports a new register based mailbox for sending messages
from host to DMCUB. This mailbox supports 64 byte commands, which makes
it compatible with the same structure as the frame buffer based mailbox.

[HOW]
The intention for reg_inbox0 is to be slot in replacement for the frame
buffer based mailbox (Inbox1). It supports all of the required features:
- Supports all messages handled by FB Inbox1
- Supports multi command batching

Reviewed-by: Joshua Aberback <joshua.aberback@amd.com>
Signed-off-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Tom Chung <chiahsuan.chung@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
  • Loading branch information
Dillon Varone authored and Alex Deucher committed Mar 10, 2025
1 parent 50bcdef commit 15d1c2e
Show file tree
Hide file tree
Showing 11 changed files with 547 additions and 274 deletions.
185 changes: 100 additions & 85 deletions drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,20 +70,28 @@ void dc_dmub_srv_destroy(struct dc_dmub_srv **dmub_srv)
}
}

void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv)
bool dc_dmub_srv_wait_for_pending(struct dc_dmub_srv *dc_dmub_srv)
{
struct dmub_srv *dmub = dc_dmub_srv->dmub;
struct dc_context *dc_ctx = dc_dmub_srv->ctx;
struct dmub_srv *dmub;
struct dc_context *dc_ctx;
enum dmub_status status;

if (!dc_dmub_srv || !dc_dmub_srv->dmub)
return false;

dc_ctx = dc_dmub_srv->ctx;
dmub = dc_dmub_srv->dmub;

do {
status = dmub_srv_wait_for_idle(dmub, 100000);
status = dmub_srv_wait_for_pending(dmub, 100000);
} while (dc_dmub_srv->ctx->dc->debug.disable_timeout && status != DMUB_STATUS_OK);

if (status != DMUB_STATUS_OK) {
DC_ERROR("Error waiting for DMUB idle: status=%d\n", status);
dc_dmub_srv_log_diagnostic_data(dc_dmub_srv);
}

return status == DMUB_STATUS_OK;
}

void dc_dmub_srv_clear_inbox0_ack(struct dc_dmub_srv *dc_dmub_srv)
Expand Down Expand Up @@ -126,7 +134,49 @@ void dc_dmub_srv_send_inbox0_cmd(struct dc_dmub_srv *dc_dmub_srv,
}
}

bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
static bool dc_dmub_srv_reg_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
unsigned int count,
union dmub_rb_cmd *cmd_list)
{
struct dc_context *dc_ctx;
struct dmub_srv *dmub;
enum dmub_status status = DMUB_STATUS_OK;
int i;

if (!dc_dmub_srv || !dc_dmub_srv->dmub)
return false;

dc_ctx = dc_dmub_srv->ctx;
dmub = dc_dmub_srv->dmub;

for (i = 0 ; i < count; i++) {
/* confirm no messages pending */
do {
status = dmub_srv_wait_for_idle(dmub, 100000);
} while (dc_dmub_srv->ctx->dc->debug.disable_timeout && status != DMUB_STATUS_OK);

/* queue command */
if (status == DMUB_STATUS_OK)
status = dmub_srv_reg_cmd_execute(dmub, &cmd_list[i]);

/* check for errors */
if (status != DMUB_STATUS_OK) {
break;
}
}

if (status != DMUB_STATUS_OK) {
if (status != DMUB_STATUS_POWER_STATE_D3) {
DC_ERROR("Error starting DMUB execution: status=%d\n", status);
dc_dmub_srv_log_diagnostic_data(dc_dmub_srv);
}
return false;
}

return true;
}

static bool dc_dmub_srv_fb_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
unsigned int count,
union dmub_rb_cmd *cmd_list)
{
Expand All @@ -143,11 +193,16 @@ bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,

for (i = 0 ; i < count; i++) {
// Queue command
status = dmub_srv_cmd_queue(dmub, &cmd_list[i]);
if (!cmd_list[i].cmd_common.header.multi_cmd_pending ||
dmub_rb_num_free(&dmub->inbox1.rb) >= count - i) {
status = dmub_srv_fb_cmd_queue(dmub, &cmd_list[i]);
} else {
status = DMUB_STATUS_QUEUE_FULL;
}

if (status == DMUB_STATUS_QUEUE_FULL) {
/* Execute and wait for queue to become empty again. */
status = dmub_srv_cmd_execute(dmub);
status = dmub_srv_fb_cmd_execute(dmub);
if (status == DMUB_STATUS_POWER_STATE_D3)
return false;

Expand All @@ -156,7 +211,7 @@ bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
} while (dc_dmub_srv->ctx->dc->debug.disable_timeout && status != DMUB_STATUS_OK);

/* Requeue the command. */
status = dmub_srv_cmd_queue(dmub, &cmd_list[i]);
status = dmub_srv_fb_cmd_queue(dmub, &cmd_list[i]);
}

if (status != DMUB_STATUS_OK) {
Expand All @@ -168,7 +223,7 @@ bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
}
}

status = dmub_srv_cmd_execute(dmub);
status = dmub_srv_fb_cmd_execute(dmub);
if (status != DMUB_STATUS_OK) {
if (status != DMUB_STATUS_POWER_STATE_D3) {
DC_ERROR("Error starting DMUB execution: status=%d\n", status);
Expand All @@ -180,6 +235,23 @@ bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
return true;
}

bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
unsigned int count,
union dmub_rb_cmd *cmd_list)
{
bool res = false;

if (dc_dmub_srv && dc_dmub_srv->dmub) {
if (dc_dmub_srv->dmub->inbox_type == DMUB_CMD_INTERFACE_REG) {
res = dc_dmub_srv_reg_cmd_list_queue_execute(dc_dmub_srv, count, cmd_list);
} else {
res = dc_dmub_srv_fb_cmd_list_queue_execute(dc_dmub_srv, count, cmd_list);
}
}

return res;
}

bool dc_dmub_srv_wait_for_idle(struct dc_dmub_srv *dc_dmub_srv,
enum dm_dmub_wait_type wait_type,
union dmub_rb_cmd *cmd_list)
Expand All @@ -202,16 +274,18 @@ bool dc_dmub_srv_wait_for_idle(struct dc_dmub_srv *dc_dmub_srv,
DC_LOG_DEBUG("No reply for DMUB command: status=%d\n", status);
if (!dmub->debug.timeout_info.timeout_occured) {
dmub->debug.timeout_info.timeout_occured = true;
dmub->debug.timeout_info.timeout_cmd = *cmd_list;
if (cmd_list)
dmub->debug.timeout_info.timeout_cmd = *cmd_list;
dmub->debug.timeout_info.timestamp = dm_get_timestamp(dc_dmub_srv->ctx);
}
dc_dmub_srv_log_diagnostic_data(dc_dmub_srv);
return false;
}

// Copy data back from ring buffer into command
if (wait_type == DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)
dmub_rb_get_return_data(&dmub->inbox1_rb, cmd_list);
if (wait_type == DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY && cmd_list) {
dmub_srv_cmd_get_response(dc_dmub_srv->dmub, cmd_list);
}
}

return true;
Expand All @@ -224,74 +298,10 @@ bool dc_dmub_srv_cmd_run(struct dc_dmub_srv *dc_dmub_srv, union dmub_rb_cmd *cmd

bool dc_dmub_srv_cmd_run_list(struct dc_dmub_srv *dc_dmub_srv, unsigned int count, union dmub_rb_cmd *cmd_list, enum dm_dmub_wait_type wait_type)
{
struct dc_context *dc_ctx;
struct dmub_srv *dmub;
enum dmub_status status;
int i;

if (!dc_dmub_srv || !dc_dmub_srv->dmub)
return false;

dc_ctx = dc_dmub_srv->ctx;
dmub = dc_dmub_srv->dmub;

for (i = 0 ; i < count; i++) {
// Queue command
status = dmub_srv_cmd_queue(dmub, &cmd_list[i]);

if (status == DMUB_STATUS_QUEUE_FULL) {
/* Execute and wait for queue to become empty again. */
status = dmub_srv_cmd_execute(dmub);
if (status == DMUB_STATUS_POWER_STATE_D3)
return false;

status = dmub_srv_wait_for_idle(dmub, 100000);
if (status != DMUB_STATUS_OK)
return false;

/* Requeue the command. */
status = dmub_srv_cmd_queue(dmub, &cmd_list[i]);
}

if (status != DMUB_STATUS_OK) {
if (status != DMUB_STATUS_POWER_STATE_D3) {
DC_ERROR("Error queueing DMUB command: status=%d\n", status);
dc_dmub_srv_log_diagnostic_data(dc_dmub_srv);
}
return false;
}
}

status = dmub_srv_cmd_execute(dmub);
if (status != DMUB_STATUS_OK) {
if (status != DMUB_STATUS_POWER_STATE_D3) {
DC_ERROR("Error starting DMUB execution: status=%d\n", status);
dc_dmub_srv_log_diagnostic_data(dc_dmub_srv);
}
if (!dc_dmub_srv_cmd_list_queue_execute(dc_dmub_srv, count, cmd_list))
return false;
}

// Wait for DMUB to process command
if (wait_type != DM_DMUB_WAIT_TYPE_NO_WAIT) {
if (dc_dmub_srv->ctx->dc->debug.disable_timeout) {
do {
status = dmub_srv_wait_for_idle(dmub, 100000);
} while (status != DMUB_STATUS_OK);
} else
status = dmub_srv_wait_for_idle(dmub, 100000);

if (status != DMUB_STATUS_OK) {
DC_LOG_DEBUG("No reply for DMUB command: status=%d\n", status);
dc_dmub_srv_log_diagnostic_data(dc_dmub_srv);
return false;
}

// Copy data back from ring buffer into command
if (wait_type == DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)
dmub_rb_get_return_data(&dmub->inbox1_rb, cmd_list);
}

return true;
return dc_dmub_srv_wait_for_idle(dc_dmub_srv, wait_type, cmd_list);
}

bool dc_dmub_srv_optimized_init_done(struct dc_dmub_srv *dc_dmub_srv)
Expand Down Expand Up @@ -1243,7 +1253,7 @@ static void dc_dmub_srv_notify_idle(const struct dc *dc, bool allow_idle)
ips_fw->signals.bits.ips1_commit,
ips_fw->signals.bits.ips2_commit);

dc_dmub_srv_wait_idle(dc->ctx->dmub_srv);
dc_dmub_srv_wait_for_idle(dc->ctx->dmub_srv, DM_DMUB_WAIT_TYPE_WAIT, NULL);

memset(&new_signals, 0, sizeof(new_signals));

Expand Down Expand Up @@ -1400,7 +1410,7 @@ static void dc_dmub_srv_exit_low_power_state(const struct dc *dc)
ips_fw->signals.bits.ips1_commit,
ips_fw->signals.bits.ips2_commit);

dmub_srv_sync_inbox1(dc->ctx->dmub_srv->dmub);
dmub_srv_sync_inboxes(dc->ctx->dmub_srv->dmub);
}
}

Expand Down Expand Up @@ -1654,7 +1664,8 @@ void dc_dmub_srv_fams2_update_config(struct dc *dc,
/* fill in generic command header */
global_cmd->header.type = DMUB_CMD__FW_ASSISTED_MCLK_SWITCH;
global_cmd->header.sub_type = DMUB_CMD__FAMS2_CONFIG;
global_cmd->header.payload_bytes = sizeof(struct dmub_rb_cmd_fams2) - sizeof(struct dmub_cmd_header);
global_cmd->header.payload_bytes =
sizeof(struct dmub_rb_cmd_fams2) - sizeof(struct dmub_cmd_header);

if (enable) {
/* send global configuration parameters */
Expand All @@ -1673,11 +1684,13 @@ void dc_dmub_srv_fams2_update_config(struct dc *dc,
/* configure command header */
stream_base_cmd->header.type = DMUB_CMD__FW_ASSISTED_MCLK_SWITCH;
stream_base_cmd->header.sub_type = DMUB_CMD__FAMS2_CONFIG;
stream_base_cmd->header.payload_bytes = sizeof(struct dmub_rb_cmd_fams2) - sizeof(struct dmub_cmd_header);
stream_base_cmd->header.payload_bytes =
sizeof(struct dmub_rb_cmd_fams2) - sizeof(struct dmub_cmd_header);
stream_base_cmd->header.multi_cmd_pending = 1;
stream_sub_state_cmd->header.type = DMUB_CMD__FW_ASSISTED_MCLK_SWITCH;
stream_sub_state_cmd->header.sub_type = DMUB_CMD__FAMS2_CONFIG;
stream_sub_state_cmd->header.payload_bytes = sizeof(struct dmub_rb_cmd_fams2) - sizeof(struct dmub_cmd_header);
stream_sub_state_cmd->header.payload_bytes =
sizeof(struct dmub_rb_cmd_fams2) - sizeof(struct dmub_cmd_header);
stream_sub_state_cmd->header.multi_cmd_pending = 1;
/* copy stream static base state */
memcpy(&stream_base_cmd->config,
Expand Down Expand Up @@ -1723,7 +1736,8 @@ void dc_dmub_srv_fams2_drr_update(struct dc *dc,
cmd.fams2_drr_update.dmub_optc_state_req.v_total_mid_frame_num = vtotal_mid_frame_num;
cmd.fams2_drr_update.dmub_optc_state_req.program_manual_trigger = program_manual_trigger;

cmd.fams2_drr_update.header.payload_bytes = sizeof(cmd.fams2_drr_update) - sizeof(cmd.fams2_drr_update.header);
cmd.fams2_drr_update.header.payload_bytes =
sizeof(cmd.fams2_drr_update) - sizeof(cmd.fams2_drr_update.header);

dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
}
Expand Down Expand Up @@ -1759,7 +1773,8 @@ void dc_dmub_srv_fams2_passthrough_flip(
/* build command header */
cmds[num_cmds].fams2_flip.header.type = DMUB_CMD__FW_ASSISTED_MCLK_SWITCH;
cmds[num_cmds].fams2_flip.header.sub_type = DMUB_CMD__FAMS2_FLIP;
cmds[num_cmds].fams2_flip.header.payload_bytes = sizeof(struct dmub_rb_cmd_fams2_flip);
cmds[num_cmds].fams2_flip.header.payload_bytes =
sizeof(struct dmub_rb_cmd_fams2_flip) - sizeof(struct dmub_cmd_header);

/* for chaining multiple commands, all but last command should set to 1 */
cmds[num_cmds].fams2_flip.header.multi_cmd_pending = 1;
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ struct dc_dmub_srv {
bool needs_idle_wake;
};

void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv);
bool dc_dmub_srv_wait_for_pending(struct dc_dmub_srv *dc_dmub_srv);

bool dc_dmub_srv_optimized_init_done(struct dc_dmub_srv *dc_dmub_srv);

Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/amd/display/dc/dc_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ void reg_sequence_wait_done(const struct dc_context *ctx)
if (offload &&
ctx->dc->debug.dmub_offload_enabled &&
!ctx->dc->debug.dmcub_emulation) {
dc_dmub_srv_wait_idle(ctx->dmub_srv);
dc_dmub_srv_wait_for_idle(ctx->dmub_srv, DM_DMUB_WAIT_TYPE_WAIT, NULL);
}
}

Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,8 @@ bool dmub_abm_save_restore(
cmd.abm_save_restore.abm_init_config_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1;
cmd.abm_save_restore.abm_init_config_data.panel_mask = panel_mask;

cmd.abm_save_restore.header.payload_bytes = sizeof(struct dmub_rb_cmd_abm_save_restore);
cmd.abm_save_restore.header.payload_bytes =
sizeof(struct dmub_rb_cmd_abm_save_restore) - sizeof(struct dmub_cmd_header);

dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);

Expand Down
19 changes: 13 additions & 6 deletions drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,9 @@ static void dmub_replay_set_power_opt_and_coasting_vtotal(struct dmub_replay *dm
memset(&cmd, 0, sizeof(cmd));
pCmd->header.type = DMUB_CMD__REPLAY;
pCmd->header.sub_type = DMUB_CMD__REPLAY_SET_POWER_OPT_AND_COASTING_VTOTAL;
pCmd->header.payload_bytes = sizeof(struct dmub_rb_cmd_replay_set_power_opt_and_coasting_vtotal);
pCmd->header.payload_bytes =
sizeof(struct dmub_rb_cmd_replay_set_power_opt_and_coasting_vtotal) -
sizeof(struct dmub_cmd_header);
pCmd->replay_set_power_opt_data.power_opt = power_opt;
pCmd->replay_set_power_opt_data.panel_inst = panel_inst;
pCmd->replay_set_coasting_vtotal_data.coasting_vtotal = (coasting_vtotal & 0xFFFF);
Expand Down Expand Up @@ -319,7 +321,8 @@ static void dmub_replay_send_cmd(struct dmub_replay *dmub,
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);
sizeof(struct dmub_rb_cmd_replay_set_timing_sync) -
sizeof(struct dmub_cmd_header);
//Cmd Body
cmd.replay_set_timing_sync.replay_set_timing_sync_data.panel_inst =
cmd_element->sync_data.panel_inst;
Expand All @@ -331,7 +334,8 @@ static void dmub_replay_send_cmd(struct dmub_replay *dmub,
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);
sizeof(struct dmub_rb_cmd_replay_set_frameupdate_timer) -
sizeof(struct dmub_cmd_header);
//Cmd Body
cmd.replay_set_frameupdate_timer.data.panel_inst =
cmd_element->panel_inst;
Expand All @@ -345,7 +349,8 @@ static void dmub_replay_send_cmd(struct dmub_replay *dmub,
cmd.replay_set_pseudo_vtotal.header.sub_type =
DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL;
cmd.replay_set_pseudo_vtotal.header.payload_bytes =
sizeof(struct dmub_rb_cmd_replay_set_pseudo_vtotal);
sizeof(struct dmub_rb_cmd_replay_set_pseudo_vtotal) -
sizeof(struct dmub_cmd_header);
//Cmd Body
cmd.replay_set_pseudo_vtotal.data.panel_inst =
cmd_element->pseudo_vtotal_data.panel_inst;
Expand All @@ -357,7 +362,8 @@ static void dmub_replay_send_cmd(struct dmub_replay *dmub,
cmd.replay_disabled_adaptive_sync_sdp.header.sub_type =
DMUB_CMD__REPLAY_DISABLED_ADAPTIVE_SYNC_SDP;
cmd.replay_disabled_adaptive_sync_sdp.header.payload_bytes =
sizeof(struct dmub_rb_cmd_replay_disabled_adaptive_sync_sdp);
sizeof(struct dmub_rb_cmd_replay_disabled_adaptive_sync_sdp) -
sizeof(struct dmub_cmd_header);
//Cmd Body
cmd.replay_disabled_adaptive_sync_sdp.data.panel_inst =
cmd_element->disabled_adaptive_sync_sdp_data.panel_inst;
Expand All @@ -369,7 +375,8 @@ static void dmub_replay_send_cmd(struct dmub_replay *dmub,
cmd.replay_set_general_cmd.header.sub_type =
DMUB_CMD__REPLAY_SET_GENERAL_CMD;
cmd.replay_set_general_cmd.header.payload_bytes =
sizeof(struct dmub_rb_cmd_replay_set_general_cmd);
sizeof(struct dmub_rb_cmd_replay_set_general_cmd) -
sizeof(struct dmub_cmd_header);
//Cmd Body
cmd.replay_set_general_cmd.data.panel_inst =
cmd_element->set_general_cmd_data.panel_inst;
Expand Down
Loading

0 comments on commit 15d1c2e

Please sign in to comment.