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

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
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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;
+28 −2
Original line number Diff line number Diff line
@@ -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;
+23 −1
Original line number Diff line number Diff line
@@ -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.
+37 −1
Original line number Diff line number Diff line
@@ -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.
	 */