Commit 9793a4a6 authored by Nicholas Kazlauskas's avatar Nicholas Kazlauskas Committed by Alex Deucher

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: default avatarNicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Signed-off-by: default avatarNicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Signed-off-by: default avatarOvidiu Bunea <Ovidiu.Bunea@amd.com>
Signed-off-by: default avatarZaeem Mohamed <zaeem.mohamed@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 4437936c
...@@ -5161,6 +5161,8 @@ void dc_set_power_state(struct dc *dc, enum dc_acpi_cm_power_state power_state) ...@@ -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_z10_restore(dc);
dc_dmub_srv_notify_fw_dc_power_state(dc->ctx->dmub_srv, power_state);
dc->hwss.init_hw(dc); dc->hwss.init_hw(dc);
if (dc->hwss.init_sys_ctx != NULL && 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) ...@@ -5172,6 +5174,8 @@ void dc_set_power_state(struct dc *dc, enum dc_acpi_cm_power_state power_state)
default: default:
ASSERT(dc->current_state->stream_count == 0); 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); dc_state_destruct(dc->current_state);
break; break;
......
...@@ -1476,7 +1476,7 @@ static void dc_dmub_srv_exit_low_power_state(const struct dc *dc) ...@@ -1476,7 +1476,7 @@ static void dc_dmub_srv_exit_low_power_state(const struct dc *dc)
ips2_exit_count); 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; 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 ...@@ -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; 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); dmub_srv_set_power_state(dmub, DMUB_POWER_STATE_D0);
else else
dmub_srv_set_power_state(dmub, DMUB_POWER_STATE_D3); 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) bool dc_dmub_srv_should_detect(struct dc_dmub_srv *dc_dmub_srv)
{ {
volatile const struct dmub_shared_state_ips_fw *ips_fw; volatile const struct dmub_shared_state_ips_fw *ips_fw;
......
...@@ -109,7 +109,29 @@ bool dc_dmub_srv_is_hw_pwr_up(struct dc_dmub_srv *dc_dmub_srv, bool wait); ...@@ -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_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. * @dc_dmub_srv_should_detect() - Checks if link detection is required.
......
...@@ -1879,7 +1879,12 @@ enum dmub_cmd_idle_opt_type { ...@@ -1879,7 +1879,12 @@ enum dmub_cmd_idle_opt_type {
/** /**
* DCN hardware notify idle. * 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 { ...@@ -1906,6 +1911,33 @@ struct dmub_rb_cmd_idle_opt_dcn_notify_idle {
struct dmub_dcn_notify_idle_cntl_data cntl_data; 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. * struct dmub_clocks - Clock update notification.
*/ */
...@@ -5298,6 +5330,10 @@ union dmub_rb_cmd { ...@@ -5298,6 +5330,10 @@ union dmub_rb_cmd {
* Definition of a DMUB_CMD__IDLE_OPT_DCN_NOTIFY_IDLE command. * Definition of a DMUB_CMD__IDLE_OPT_DCN_NOTIFY_IDLE command.
*/ */
struct dmub_rb_cmd_idle_opt_dcn_notify_idle idle_opt_notify_idle; 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. * Definition of a DMUB_CMD__REPLAY_COPY_SETTINGS command.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment