From 6ffaa6fcd06add240abe681f9b6da7fef742b85d Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin Date: Fri, 8 Mar 2019 20:16:45 -0500 Subject: [PATCH] drm/amd/display: fix odm pipe management There are issues removing surfaces/streams when odm is active. This is a step to fix that Signed-off-by: Dmytro Laktyushkin Reviewed-by: Tony Cheng Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/core/dc_resource.c | 58 ++++++++++++++++--- drivers/gpu/drm/amd/display/dc/inc/resource.h | 2 + 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 13f99b11aaa6..3c9df3703e46 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1251,6 +1251,40 @@ bool dc_add_plane_to_context( return true; } +struct pipe_ctx *dc_res_get_odm_bottom_pipe(struct pipe_ctx *pipe_ctx) +{ + struct pipe_ctx *bottom_pipe = pipe_ctx->bottom_pipe; + + /* ODM should only be updated once per otg */ + if (pipe_ctx->top_pipe) + return NULL; + + while (bottom_pipe) { + if (bottom_pipe->stream_res.opp != pipe_ctx->stream_res.opp) + break; + bottom_pipe = bottom_pipe->bottom_pipe; + } + + return bottom_pipe; +} + +static bool dc_res_is_odm_bottom_pipe(struct pipe_ctx *pipe_ctx) +{ + struct pipe_ctx *top_pipe = pipe_ctx->top_pipe; + bool result = false; + + if (top_pipe && top_pipe->stream_res.opp == pipe_ctx->stream_res.opp) + return false; + + while (top_pipe) { + if (!top_pipe->top_pipe && top_pipe->stream_res.opp != pipe_ctx->stream_res.opp) + result = true; + top_pipe = top_pipe->top_pipe; + } + + return result; +} + bool dc_remove_plane_from_context( const struct dc *dc, struct dc_stream_state *stream, @@ -1274,10 +1308,14 @@ bool dc_remove_plane_from_context( /* release pipe for plane*/ for (i = pool->pipe_count - 1; i >= 0; i--) { - struct pipe_ctx *pipe_ctx; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - if (context->res_ctx.pipe_ctx[i].plane_state == plane_state) { - pipe_ctx = &context->res_ctx.pipe_ctx[i]; + if (pipe_ctx->plane_state == plane_state) { + if (dc_res_is_odm_bottom_pipe(pipe_ctx)) { + pipe_ctx->plane_state = NULL; + pipe_ctx->bottom_pipe = NULL; + continue; + } if (pipe_ctx->top_pipe) pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe; @@ -1293,11 +1331,10 @@ bool dc_remove_plane_from_context( * For head pipe detach surfaces from pipe for tail * pipe just zero it out */ - if (!pipe_ctx->top_pipe || (!pipe_ctx->top_pipe->top_pipe && - pipe_ctx->top_pipe->stream_res.opp != pipe_ctx->stream_res.opp)) { - pipe_ctx->top_pipe = NULL; + if (!pipe_ctx->top_pipe) { pipe_ctx->plane_state = NULL; - pipe_ctx->bottom_pipe = NULL; + if (!dc_res_get_odm_bottom_pipe(pipe_ctx)) + pipe_ctx->bottom_pipe = NULL; } else { memset(pipe_ctx, 0, sizeof(*pipe_ctx)); } @@ -1703,6 +1740,9 @@ enum dc_status dc_remove_stream_from_ctx( for (i = 0; i < MAX_PIPES; i++) { if (new_ctx->res_ctx.pipe_ctx[i].stream == stream && !new_ctx->res_ctx.pipe_ctx[i].top_pipe) { + struct pipe_ctx *odm_pipe = + dc_res_get_odm_bottom_pipe(&new_ctx->res_ctx.pipe_ctx[i]); + del_pipe = &new_ctx->res_ctx.pipe_ctx[i]; ASSERT(del_pipe->stream_res.stream_enc); @@ -1727,6 +1767,10 @@ enum dc_status dc_remove_stream_from_ctx( dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream); memset(del_pipe, 0, sizeof(*del_pipe)); + if (odm_pipe) + memset(odm_pipe, 0, sizeof(*odm_pipe)); + + break; } } diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h index 0086a2f1d21a..62e00a9f3184 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/resource.h +++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h @@ -172,4 +172,6 @@ void update_audio_usage( unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format); +struct pipe_ctx *dc_res_get_odm_bottom_pipe(struct pipe_ctx *pipe_ctx); + #endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_RESOURCE_H_ */ -- 2.30.2