diff options
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.c | 154 |
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); +} + |