]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
drm/amd/display: Notify DMCUB of D0/D3 state
authorNicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Fri, 21 Jun 2024 20:11:28 +0000 (16:11 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 27 Aug 2024 21:53:51 +0000 (17:53 -0400)
[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>
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h

index c8dabb081b3d932e40bb2404ece35798b79e4e4e..e07e47d7466463c4f82be6b09d6dc20b0f09d3e9 100644 (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;
index b1265124608bec38bc695c0bc0e27d6c1d79b4d7..1e7de0f03290a30e9083f869b36a3d14906b2ecb 100644 (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;
index 580940222777eac187e8970ba004f733fa040519..42f0cb672d8bb2ec1d36a934671b0e8cac33278b 100644 (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.
index c5f99cbff0b6478c5fe6b2d75eb87ebd14322747..f5dda1d69ae043d224449fd51e59af991ac4f815 100644 (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.
         */