[why] In PSR-SU design, the DMUB FW handles the combination of multiple dirty rectangles. [how] - create DC dmub update dirty rectangle helper which sends the dirty rectangles per pipe from DC to DMUB, and DMUB FW will handle to combine the dirty RECTs - call the helper from DC commit plane update function. Signed-off-by: David Zhang <dingchen.zhang@xxxxxxx> --- drivers/gpu/drm/amd/display/dc/core/dc.c | 54 ++++++++++++++++++++++ drivers/gpu/drm/amd/display/dc/dc.h | 3 ++ drivers/gpu/drm/amd/display/dc/dc_stream.h | 5 ++ 3 files changed, 62 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index c2fcd67bcc4d..0649d84b71b6 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -72,6 +72,9 @@ #include "dmub/dmub_srv.h" #include "i2caux_interface.h" + +#include "dce/dmub_psr.h" + #include "dce/dmub_hw_lock_mgr.h" #include "dc_trace.h" @@ -2842,6 +2845,55 @@ static void commit_planes_do_stream_update(struct dc *dc, } } +void dc_dmub_update_dirty_rect(struct dc *dc, + int surface_count, + struct dc_stream_state *stream, + struct dc_surface_update *srf_updates, + struct dc_state *context) +{ + union dmub_rb_cmd cmd; + struct dc_context *dc_ctx = dc->ctx; + struct dmub_cmd_update_dirty_rect_data *update_dirty_rect; + unsigned int i, j; + + if (stream->link->psr_settings.psr_version != DC_PSR_VERSION_SU_1) + return; + + memset(&cmd, 0x0, sizeof(cmd)); + cmd.update_dirty_rect.header.type = DMUB_CMD__UPDATE_DIRTY_RECT; + cmd.update_dirty_rect.header.sub_type = 0; + cmd.update_dirty_rect.header.payload_bytes = + sizeof(cmd.update_dirty_rect) - + sizeof(cmd.update_dirty_rect.header); + update_dirty_rect = &cmd.update_dirty_rect.update_dirty_rect_data; + for (i = 0; i < surface_count; i++) { + struct dc_plane_state *plane_state = srf_updates[i].surface; + const struct dc_flip_addrs *flip_addr = srf_updates[i].flip_addr; + + if (!srf_updates[i].surface || !flip_addr) + continue; + /* Do not send in immediate flip mode */ + if (srf_updates[i].surface->flip_immediate) + continue; + + update_dirty_rect->dirty_rect_count = flip_addr->dirty_rect_count; + memcpy(update_dirty_rect->src_dirty_rects, flip_addr->dirty_rects, + sizeof(flip_addr->dirty_rects)); + for (j = 0; j < dc->res_pool->pipe_count; j++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; + + if (pipe_ctx->stream != stream) + continue; + if (pipe_ctx->plane_state != plane_state) + continue; + + update_dirty_rect->pipe_idx = j; + dc_dmub_srv_cmd_queue(dc_ctx->dmub_srv, &cmd); + dc_dmub_srv_cmd_execute(dc_ctx->dmub_srv); + } + } +} + static void commit_planes_for_stream(struct dc *dc, struct dc_surface_update *srf_updates, int surface_count, @@ -2934,6 +2986,8 @@ static void commit_planes_for_stream(struct dc *dc, */ dc->hwss.pipe_control_lock(dc, top_pipe_to_program, true); + dc_dmub_update_dirty_rect(dc, surface_count, stream, srf_updates, context); + // Stream updates if (stream_update) commit_planes_do_stream_update(dc, stream, stream_update, update_type, context); diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 942bfb8fd851..85f3303e7843 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -1134,12 +1134,15 @@ void dc_3dlut_func_retain(struct dc_3dlut *lut); * in cases such as Stereo 3D, Planar YUV, etc. Other per-flip attributes such * as frame durations and DCC format can also be set. */ +#define DC_MAX_DIRTY_RECTS 3 struct dc_flip_addrs { struct dc_plane_address address; unsigned int flip_timestamp_in_us; bool flip_immediate; /* TODO: add flip duration for FreeSync */ bool triplebuffer_flips; + unsigned int dirty_rect_count; + struct rect dirty_rects[DC_MAX_DIRTY_RECTS]; }; void dc_post_update_surfaces_to_stream( diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 58941f4defb3..58036469c62a 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -529,4 +529,9 @@ bool dc_stream_get_crtc_position(struct dc *dc, struct pipe_ctx *dc_stream_get_pipe_ctx(struct dc_stream_state *stream); +void dc_dmub_update_dirty_rect(struct dc *dc, + int surface_count, + struct dc_stream_state *stream, + struct dc_surface_update *srf_updates, + struct dc_state *context); #endif /* DC_STREAM_H_ */ -- 2.25.1