drm/amd/display: Notify DMCUB of D0/D3 state

[Why]
We want to avoid arming the HPD timer in firmware when preparing for
S0i3 entry when DC is considered in D3.

[How]
Notify DMCUB of the power state transitions so it can decide to arm
the HPD timer for idle in DCN35 only in D0.

Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Signed-off-by: Ovidiu Bunea <Ovidiu.Bunea@amd.com>
Signed-off-by: Zaeem Mohamed <zaeem.mohamed@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Nicholas Kazlauskas 2024-06-21 16:11:28 -04:00 committed by Alex Deucher
parent 4437936c6b
commit 9793a4a6e5
4 changed files with 92 additions and 4 deletions

View File

@ -5161,6 +5161,8 @@ void dc_set_power_state(struct dc *dc, enum dc_acpi_cm_power_state power_state)
dc_z10_restore(dc);
dc_dmub_srv_notify_fw_dc_power_state(dc->ctx->dmub_srv, power_state);
dc->hwss.init_hw(dc);
if (dc->hwss.init_sys_ctx != NULL &&
@ -5172,6 +5174,8 @@ void dc_set_power_state(struct dc *dc, enum dc_acpi_cm_power_state power_state)
default:
ASSERT(dc->current_state->stream_count == 0);
dc_dmub_srv_notify_fw_dc_power_state(dc->ctx->dmub_srv, power_state);
dc_state_destruct(dc->current_state);
break;

View File

@ -1476,7 +1476,7 @@ static void dc_dmub_srv_exit_low_power_state(const struct dc *dc)
ips2_exit_count);
}
void dc_dmub_srv_set_power_state(struct dc_dmub_srv *dc_dmub_srv, enum dc_acpi_cm_power_state powerState)
void dc_dmub_srv_set_power_state(struct dc_dmub_srv *dc_dmub_srv, enum dc_acpi_cm_power_state power_state)
{
struct dmub_srv *dmub;
@ -1485,12 +1485,38 @@ void dc_dmub_srv_set_power_state(struct dc_dmub_srv *dc_dmub_srv, enum dc_acpi_c
dmub = dc_dmub_srv->dmub;
if (powerState == DC_ACPI_CM_POWER_STATE_D0)
if (power_state == DC_ACPI_CM_POWER_STATE_D0)
dmub_srv_set_power_state(dmub, DMUB_POWER_STATE_D0);
else
dmub_srv_set_power_state(dmub, DMUB_POWER_STATE_D3);
}
void dc_dmub_srv_notify_fw_dc_power_state(struct dc_dmub_srv *dc_dmub_srv,
enum dc_acpi_cm_power_state power_state)
{
union dmub_rb_cmd cmd;
if (!dc_dmub_srv)
return;
memset(&cmd, 0, sizeof(cmd));
cmd.idle_opt_set_dc_power_state.header.type = DMUB_CMD__IDLE_OPT;
cmd.idle_opt_set_dc_power_state.header.sub_type = DMUB_CMD__IDLE_OPT_SET_DC_POWER_STATE;
cmd.idle_opt_set_dc_power_state.header.payload_bytes =
sizeof(cmd.idle_opt_set_dc_power_state) - sizeof(cmd.idle_opt_set_dc_power_state.header);
if (power_state == DC_ACPI_CM_POWER_STATE_D0) {
cmd.idle_opt_set_dc_power_state.data.power_state = DMUB_IDLE_OPT_DC_POWER_STATE_D0;
} else if (power_state == DC_ACPI_CM_POWER_STATE_D3) {
cmd.idle_opt_set_dc_power_state.data.power_state = DMUB_IDLE_OPT_DC_POWER_STATE_D3;
} else {
cmd.idle_opt_set_dc_power_state.data.power_state = DMUB_IDLE_OPT_DC_POWER_STATE_UNKNOWN;
}
dc_wake_and_execute_dmub_cmd(dc_dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
}
bool dc_dmub_srv_should_detect(struct dc_dmub_srv *dc_dmub_srv)
{
volatile const struct dmub_shared_state_ips_fw *ips_fw;

View File

@ -109,7 +109,29 @@ bool dc_dmub_srv_is_hw_pwr_up(struct dc_dmub_srv *dc_dmub_srv, bool wait);
void dc_dmub_srv_apply_idle_power_optimizations(const struct dc *dc, bool allow_idle);
void dc_dmub_srv_set_power_state(struct dc_dmub_srv *dc_dmub_srv, enum dc_acpi_cm_power_state powerState);
/**
* dc_dmub_srv_set_power_state() - Sets the power state for DMUB service.
*
* Controls whether messaging the DMCUB or interfacing with it via HW register
* interaction is permittable.
*
* @dc_dmub_srv - The DC DMUB service pointer
* @power_state - the DC power state
*/
void dc_dmub_srv_set_power_state(struct dc_dmub_srv *dc_dmub_srv, enum dc_acpi_cm_power_state power_state);
/**
* dc_dmub_srv_notify_fw_dc_power_state() - Notifies firmware of the DC power state.
*
* Differs from dc_dmub_srv_set_power_state in that it needs to access HW in order
* to message DMCUB of the state transition. Should come after the D0 exit and
* before D3 set power state.
*
* @dc_dmub_srv - The DC DMUB service pointer
* @power_state - the DC power state
*/
void dc_dmub_srv_notify_fw_dc_power_state(struct dc_dmub_srv *dc_dmub_srv,
enum dc_acpi_cm_power_state power_state);
/**
* @dc_dmub_srv_should_detect() - Checks if link detection is required.

View File

@ -1879,7 +1879,12 @@ enum dmub_cmd_idle_opt_type {
/**
* DCN hardware notify idle.
*/
DMUB_CMD__IDLE_OPT_DCN_NOTIFY_IDLE = 2
DMUB_CMD__IDLE_OPT_DCN_NOTIFY_IDLE = 2,
/**
* DCN hardware notify power state.
*/
DMUB_CMD__IDLE_OPT_SET_DC_POWER_STATE = 3,
};
/**
@ -1906,6 +1911,33 @@ struct dmub_rb_cmd_idle_opt_dcn_notify_idle {
struct dmub_dcn_notify_idle_cntl_data cntl_data;
};
/**
* enum dmub_idle_opt_dc_power_state - DC power states.
*/
enum dmub_idle_opt_dc_power_state {
DMUB_IDLE_OPT_DC_POWER_STATE_UNKNOWN = 0,
DMUB_IDLE_OPT_DC_POWER_STATE_D0 = 1,
DMUB_IDLE_OPT_DC_POWER_STATE_D1 = 2,
DMUB_IDLE_OPT_DC_POWER_STATE_D2 = 4,
DMUB_IDLE_OPT_DC_POWER_STATE_D3 = 8,
};
/**
* struct dmub_idle_opt_set_dc_power_state_data - Data passed to FW in a DMUB_CMD__IDLE_OPT_SET_DC_POWER_STATE command.
*/
struct dmub_idle_opt_set_dc_power_state_data {
uint8_t power_state; /**< power state */
uint8_t pad[3]; /**< padding */
};
/**
* struct dmub_rb_cmd_idle_opt_set_dc_power_state - Data passed to FW in a DMUB_CMD__IDLE_OPT_SET_DC_POWER_STATE command.
*/
struct dmub_rb_cmd_idle_opt_set_dc_power_state {
struct dmub_cmd_header header; /**< header */
struct dmub_idle_opt_set_dc_power_state_data data;
};
/**
* struct dmub_clocks - Clock update notification.
*/
@ -5298,6 +5330,10 @@ union dmub_rb_cmd {
* Definition of a DMUB_CMD__IDLE_OPT_DCN_NOTIFY_IDLE command.
*/
struct dmub_rb_cmd_idle_opt_dcn_notify_idle idle_opt_notify_idle;
/**
* Definition of a DMUB_CMD__IDLE_OPT_SET_DC_POWER_STATE command.
*/
struct dmub_rb_cmd_idle_opt_set_dc_power_state idle_opt_set_dc_power_state;
/*
* Definition of a DMUB_CMD__REPLAY_COPY_SETTINGS command.
*/