From: Nicholas Kazlauskas <nicholas.kazlaus...@amd.com>

[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.kazlaus...@amd.com>
Signed-off-by: Nicholas Kazlauskas <nicholas.kazlaus...@amd.com>
Signed-off-by: Ovidiu Bunea <ovidiu.bu...@amd.com>
Signed-off-by: Zaeem Mohamed <zaeem.moha...@amd.com>
---
 drivers/gpu/drm/amd/display/dc/core/dc.c      |  4 ++
 drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c  | 30 ++++++++++++++-
 drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h  | 24 +++++++++++-
 .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h   | 38 ++++++++++++++++++-
 4 files changed, 92 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c 
b/drivers/gpu/drm/amd/display/dc/core/dc.c
index c8dabb081b3d..e07e47d74664 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -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;
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c 
b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
index b1265124608b..1e7de0f03290 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
@@ -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;
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h 
b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
index 580940222777..42f0cb672d8b 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
@@ -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.
diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h 
b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
index c5f99cbff0b6..f5dda1d69ae0 100644
--- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
+++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
@@ -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.
         */
-- 
2.34.1

Reply via email to