summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c')
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c154
1 files changed, 138 insertions, 16 deletions
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 4c5ef3ef8dbd..ba142bef626b 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
@@ -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,123 @@ 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)
+{
+ const uint32_t max_num_polls = 10000;
+ uint32_t allow_state = 0;
+ uint32_t commit_state = 0;
+ uint32_t i;
+
+ 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);
+
+ for (i = 0; i < max_num_polls; ++i) {
+ commit_state = dc->hwss.get_idle_state(dc);
+ if (!(commit_state & DMUB_IPS2_COMMIT_MASK))
+ break;
+
+ udelay(1);
+ }
+ ASSERT(i < max_num_polls);
+
+ if (!dc_dmub_srv_is_hw_pwr_up(dc->ctx->dmub_srv, true))
+ ASSERT(0);
+
+ /* TODO: See if we can return early here - IPS2 should go
+ * back directly to IPS0 and clear the flags, but it will
+ * be safer to directly notify DMCUB of this.
+ */
+ allow_state = dc->hwss.get_idle_state(dc);
+ }
+ }
+
+ dc_dmub_srv_notify_idle(dc, false);
+ if (allow_state & DMUB_IPS1_ALLOW_MASK) {
+ for (i = 0; i < max_num_polls; ++i) {
+ commit_state = dc->hwss.get_idle_state(dc);
+ if (!(commit_state & DMUB_IPS1_COMMIT_MASK))
+ break;
+
+ udelay(1);
+ }
+ ASSERT(i < max_num_polls);
+ }
+ }
+
+ if (!dc_dmub_srv_is_hw_pwr_up(dc->ctx->dmub_srv, true))
+ ASSERT(0);
+}
+