Merge tag 'amd-drm-next-6.7-2023-10-13' of https://gitlab.freedesktop.org/agd5f/linux...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / amd / display / dc / dc_dmub_srv.c
index 4c5ef3ef8dbdd78bf93a9871e9ee95f70477efe7..4fd3f09432be4fe92a4ee1336eca4144a21e4c2e 100644 (file)
@@ -32,6 +32,7 @@
 #include "../basics/conversion.h"
 #include "cursor_reg_cache.h"
 #include "resource.h"
+#include "clk_mgr.h"
 
 #define CTX dc_dmub_srv->ctx
 #define DC_LOGGER CTX->logger
@@ -79,43 +80,43 @@ void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv)
        }
 }
 
-void dc_dmub_srv_clear_inbox0_ack(struct dc_dmub_srv *dmub_srv)
+void dc_dmub_srv_clear_inbox0_ack(struct dc_dmub_srv *dc_dmub_srv)
 {
-       struct dmub_srv *dmub = dmub_srv->dmub;
-       struct dc_context *dc_ctx = dmub_srv->ctx;
+       struct dmub_srv *dmub = dc_dmub_srv->dmub;
+       struct dc_context *dc_ctx = dc_dmub_srv->ctx;
        enum dmub_status status = DMUB_STATUS_OK;
 
        status = dmub_srv_clear_inbox0_ack(dmub);
        if (status != DMUB_STATUS_OK) {
                DC_ERROR("Error clearing INBOX0 ack: status=%d\n", status);
-               dc_dmub_srv_log_diagnostic_data(dmub_srv);
+               dc_dmub_srv_log_diagnostic_data(dc_dmub_srv);
        }
 }
 
-void dc_dmub_srv_wait_for_inbox0_ack(struct dc_dmub_srv *dmub_srv)
+void dc_dmub_srv_wait_for_inbox0_ack(struct dc_dmub_srv *dc_dmub_srv)
 {
-       struct dmub_srv *dmub = dmub_srv->dmub;
-       struct dc_context *dc_ctx = dmub_srv->ctx;
+       struct dmub_srv *dmub = dc_dmub_srv->dmub;
+       struct dc_context *dc_ctx = dc_dmub_srv->ctx;
        enum dmub_status status = DMUB_STATUS_OK;
 
        status = dmub_srv_wait_for_inbox0_ack(dmub, 100000);
        if (status != DMUB_STATUS_OK) {
                DC_ERROR("Error waiting for INBOX0 HW Lock Ack\n");
-               dc_dmub_srv_log_diagnostic_data(dmub_srv);
+               dc_dmub_srv_log_diagnostic_data(dc_dmub_srv);
        }
 }
 
-void dc_dmub_srv_send_inbox0_cmd(struct dc_dmub_srv *dmub_srv,
-               union dmub_inbox0_data_register data)
+void dc_dmub_srv_send_inbox0_cmd(struct dc_dmub_srv *dc_dmub_srv,
+                                union dmub_inbox0_data_register data)
 {
-       struct dmub_srv *dmub = dmub_srv->dmub;
-       struct dc_context *dc_ctx = dmub_srv->ctx;
+       struct dmub_srv *dmub = dc_dmub_srv->dmub;
+       struct dc_context *dc_ctx = dc_dmub_srv->ctx;
        enum dmub_status status = DMUB_STATUS_OK;
 
        status = dmub_srv_send_inbox0_cmd(dmub, data);
        if (status != DMUB_STATUS_OK) {
                DC_ERROR("Error sending INBOX0 cmd\n");
-               dc_dmub_srv_log_diagnostic_data(dmub_srv);
+               dc_dmub_srv_log_diagnostic_data(dc_dmub_srv);
        }
 }
 
@@ -552,7 +553,8 @@ static void populate_subvp_cmd_vblank_pipe_info(struct dc *dc,
        pipe_data->pipe_config.vblank_data.vblank_end =
                        vblank_pipe->stream->timing.v_total - vblank_pipe->stream->timing.v_front_porch - vblank_pipe->stream->timing.v_addressable;
 
-       if (vblank_pipe->stream->ignore_msa_timing_param)
+       if (vblank_pipe->stream->ignore_msa_timing_param &&
+               (vblank_pipe->stream->allow_freesync || vblank_pipe->stream->vrr_active_variable || vblank_pipe->stream->vrr_active_fixed))
                populate_subvp_cmd_drr_info(dc, pipe, vblank_pipe, pipe_data);
 }
 
@@ -645,7 +647,8 @@ static void populate_subvp_cmd_pipe_info(struct dc *dc,
                        main_timing->v_total - main_timing->v_front_porch - main_timing->v_addressable;
        pipe_data->pipe_config.subvp_data.mall_region_lines = phantom_timing->v_addressable;
        pipe_data->pipe_config.subvp_data.main_pipe_index = subvp_pipe->stream_res.tg->inst;
-       pipe_data->pipe_config.subvp_data.is_drr = subvp_pipe->stream->ignore_msa_timing_param;
+       pipe_data->pipe_config.subvp_data.is_drr = subvp_pipe->stream->ignore_msa_timing_param &&
+               (subvp_pipe->stream->allow_freesync || subvp_pipe->stream->vrr_active_variable || subvp_pipe->stream->vrr_active_fixed);
 
        /* Calculate the scaling factor from the src and dst height.
         * e.g. If 3840x2160 being downscaled to 1920x1080, the scaling factor is 1/2.
@@ -1054,4 +1057,107 @@ void dc_dmub_srv_enable_dpia_trace(const struct dc *dc)
        }
 
        DC_LOG_DEBUG("Enabled DPIA trace\n");
-}
\ No newline at end of file
+}
+
+void dc_dmub_srv_subvp_save_surf_addr(const struct dc_dmub_srv *dc_dmub_srv, const struct dc_plane_address *addr, uint8_t subvp_index)
+{
+       dmub_srv_subvp_save_surf_addr(dc_dmub_srv->dmub, addr, subvp_index);
+}
+
+bool dc_dmub_srv_is_hw_pwr_up(struct dc_dmub_srv *dc_dmub_srv, bool wait)
+{
+       struct dc_context *dc_ctx = dc_dmub_srv->ctx;
+       enum dmub_status status;
+
+       if (dc_dmub_srv->ctx->dc->debug.dmcub_emulation)
+               return true;
+
+       if (wait) {
+               status = dmub_srv_wait_for_hw_pwr_up(dc_dmub_srv->dmub, 500000);
+               if (status != DMUB_STATUS_OK) {
+                       DC_ERROR("Error querying DMUB hw power up status: error=%d\n", status);
+                       return false;
+               }
+       } else
+               return dmub_srv_is_hw_pwr_up(dc_dmub_srv->dmub);
+
+       return true;
+}
+
+void dc_dmub_srv_notify_idle(const struct dc *dc, bool allow_idle)
+{
+       union dmub_rb_cmd cmd = {0};
+
+       if (dc->debug.dmcub_emulation)
+               return;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.idle_opt_notify_idle.header.type = DMUB_CMD__IDLE_OPT;
+       cmd.idle_opt_notify_idle.header.sub_type = DMUB_CMD__IDLE_OPT_DCN_NOTIFY_IDLE;
+       cmd.idle_opt_notify_idle.header.payload_bytes =
+               sizeof(cmd.idle_opt_notify_idle) -
+               sizeof(cmd.idle_opt_notify_idle.header);
+
+       cmd.idle_opt_notify_idle.cntl_data.driver_idle = allow_idle;
+
+       if (allow_idle) {
+               if (dc->hwss.set_idle_state)
+                       dc->hwss.set_idle_state(dc, true);
+       }
+
+       dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+}
+
+void dc_dmub_srv_exit_low_power_state(const struct dc *dc)
+{
+       uint32_t allow_state = 0;
+       uint32_t commit_state = 0;
+
+       if (dc->debug.dmcub_emulation)
+               return;
+
+       if (!dc->idle_optimizations_allowed)
+               return;
+
+       if (dc->hwss.get_idle_state &&
+               dc->hwss.set_idle_state &&
+               dc->clk_mgr->funcs->exit_low_power_state) {
+
+               allow_state = dc->hwss.get_idle_state(dc);
+               dc->hwss.set_idle_state(dc, false);
+
+               if (allow_state & DMUB_IPS2_ALLOW_MASK) {
+                       // Wait for evaluation time
+                       udelay(dc->debug.ips2_eval_delay_us);
+                       commit_state = dc->hwss.get_idle_state(dc);
+                       if (commit_state & DMUB_IPS2_COMMIT_MASK) {
+                               // Tell PMFW to exit low power state
+                               dc->clk_mgr->funcs->exit_low_power_state(dc->clk_mgr);
+
+                               // Wait for IPS2 entry upper bound
+                               udelay(dc->debug.ips2_entry_delay_us);
+                               dc->clk_mgr->funcs->exit_low_power_state(dc->clk_mgr);
+
+                               do {
+                                       commit_state = dc->hwss.get_idle_state(dc);
+                               } while (commit_state & DMUB_IPS2_COMMIT_MASK);
+
+                               if (!dc_dmub_srv_is_hw_pwr_up(dc->ctx->dmub_srv, true))
+                                       ASSERT(0);
+
+                               return;
+                       }
+               }
+
+               dc_dmub_srv_notify_idle(dc, false);
+               if (allow_state & DMUB_IPS1_ALLOW_MASK) {
+                       do {
+                               commit_state = dc->hwss.get_idle_state(dc);
+                       } while (commit_state & DMUB_IPS1_COMMIT_MASK);
+               }
+       }
+
+       if (!dc_dmub_srv_is_hw_pwr_up(dc->ctx->dmub_srv, true))
+               ASSERT(0);
+}
+